Skip to content

Commit 7fe04da

Browse files
committed
WIP add support for building in "decoupled" mode
1 parent 8deb554 commit 7fe04da

File tree

12 files changed

+468
-369
lines changed

12 files changed

+468
-369
lines changed

Cargo.lock

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ default = [ "macros", "runtime-async-std" ]
3939
macros = [ "sqlx-macros" ]
4040
tls = [ "sqlx-core/tls" ]
4141

42+
# offline building support in `sqlx-macros`
43+
offline = ["sqlx-macros/offline"]
44+
4245
# intended mainly for CI and docs
4346
all = [ "tls", "all-database", "all-type" ]
4447
all-database = [ "mysql", "sqlite", "postgres" ]

sqlx-macros/Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ proc-macro = true
1919
default = [ "runtime-async-std" ]
2020

2121
runtime-async-std = [ "sqlx/runtime-async-std", "async-std" ]
22-
runtime-tokio = [ "sqlx/runtime-tokio", "tokio", "lazy_static" ]
22+
runtime-tokio = [ "sqlx/runtime-tokio", "tokio", "once_cell" ]
23+
24+
# offline building support
25+
offline = ["serde", "serde_json", "hex", "sha2"]
2326

2427
# database
2528
mysql = [ "sqlx/mysql" ]
@@ -39,10 +42,13 @@ async-std = { version = "1.5.0", default-features = false, optional = true }
3942
tokio = { version = "0.2.13", default-features = false, features = [ "rt-threaded" ], optional = true }
4043
dotenv = { version = "0.15.0", default-features = false }
4144
futures = { version = "0.3.4", default-features = false, features = [ "executor" ] }
45+
hex = { version = "0.4.2", optional = true }
4246
proc-macro2 = { version = "1.0.9", default-features = false }
4347
sqlx = { version = "0.3.4", default-features = false, path = "../sqlx-core", package = "sqlx-core" }
48+
serde = { version = "1.0", optional = true }
4449
serde_json = { version = "1.0", features = [ "raw_value" ], optional = true }
50+
sha2 = { verison = "0.8.1", optional = true }
4551
syn = { version = "1.0.16", default-features = false, features = [ "full" ] }
4652
quote = { version = "1.0.2", default-features = false }
4753
url = { version = "2.1.1", default-features = false }
48-
lazy_static = { version = "1.4.0", optional = true }
54+
once_cell = { version = "1.3", features = ["std"], optional = true }

sqlx-macros/src/lib.rs

Lines changed: 13 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,6 @@ mod runtime;
2424

2525
use query_macros::*;
2626

27-
#[cfg(feature = "runtime-tokio")]
28-
lazy_static::lazy_static! {
29-
static ref BASIC_RUNTIME: tokio::runtime::Runtime = {
30-
tokio::runtime::Builder::new()
31-
.threaded_scheduler()
32-
.enable_io()
33-
.enable_time()
34-
.build()
35-
.expect("failed to build tokio runtime")
36-
};
37-
}
38-
39-
#[cfg(feature = "runtime-tokio")]
40-
fn block_on<F: std::future::Future>(future: F) -> F::Output {
41-
BASIC_RUNTIME.enter(|| futures::executor::block_on(future))
42-
}
43-
4427
fn macro_result(tokens: proc_macro2::TokenStream) -> TokenStream {
4528
quote!(
4629
macro_rules! macro_result {
@@ -50,117 +33,21 @@ fn macro_result(tokens: proc_macro2::TokenStream) -> TokenStream {
5033
.into()
5134
}
5235

53-
macro_rules! async_macro (
54-
($db:ident, $input:ident: $ty:ty => $expr:expr) => {{
55-
let $input = match syn::parse::<$ty>($input) {
56-
Ok(input) => input,
57-
Err(e) => return macro_result(e.to_compile_error()),
58-
};
59-
60-
let res: Result<proc_macro2::TokenStream> = block_on(async {
61-
use sqlx::connection::Connect;
62-
63-
let db_url = Url::parse(&dotenv::var("DATABASE_URL").map_err(|_| "DATABASE_URL not set")?)?;
64-
65-
match db_url.scheme() {
66-
#[cfg(feature = "sqlite")]
67-
"sqlite" => {
68-
let $db = sqlx::sqlite::SqliteConnection::connect(db_url.as_str())
69-
.await
70-
.map_err(|e| format!("failed to connect to database: {}", e))?;
71-
72-
$expr.await
73-
}
74-
#[cfg(not(feature = "sqlite"))]
75-
"sqlite" => Err(format!(
76-
"DATABASE_URL {} has the scheme of a SQLite database but the `sqlite` \
77-
feature of sqlx was not enabled",
78-
db_url
79-
).into()),
80-
#[cfg(feature = "postgres")]
81-
"postgresql" | "postgres" => {
82-
let $db = sqlx::postgres::PgConnection::connect(db_url.as_str())
83-
.await
84-
.map_err(|e| format!("failed to connect to database: {}", e))?;
85-
86-
$expr.await
87-
}
88-
#[cfg(not(feature = "postgres"))]
89-
"postgresql" | "postgres" => Err(format!(
90-
"DATABASE_URL {} has the scheme of a Postgres database but the `postgres` \
91-
feature of sqlx was not enabled",
92-
db_url
93-
).into()),
94-
#[cfg(feature = "mysql")]
95-
"mysql" | "mariadb" => {
96-
let $db = sqlx::mysql::MySqlConnection::connect(db_url.as_str())
97-
.await
98-
.map_err(|e| format!("failed to connect to database: {}", e))?;
99-
100-
$expr.await
101-
}
102-
#[cfg(not(feature = "mysql"))]
103-
"mysql" | "mariadb" => Err(format!(
104-
"DATABASE_URL {} has the scheme of a MySQL/MariaDB database but the `mysql` \
105-
feature of sqlx was not enabled",
106-
db_url
107-
).into()),
108-
scheme => Err(format!("unexpected scheme {:?} in DATABASE_URL {}", scheme, db_url).into()),
109-
}
110-
});
111-
112-
match res {
113-
Ok(ts) => ts.into(),
114-
Err(e) => {
115-
if let Some(parse_err) = e.downcast_ref::<syn::Error>() {
116-
macro_result(parse_err.to_compile_error())
117-
} else {
118-
let msg = e.to_string();
119-
macro_result(quote!(compile_error!(#msg)))
120-
}
121-
}
122-
}
123-
}}
124-
);
125-
126-
#[proc_macro]
127-
#[allow(unused_variables)]
128-
pub fn query(input: TokenStream) -> TokenStream {
129-
#[allow(unused_variables)]
130-
async_macro!(db, input: QueryMacroInput => expand_query(input, db))
131-
}
132-
133-
#[proc_macro]
134-
#[allow(unused_variables)]
135-
pub fn query_file(input: TokenStream) -> TokenStream {
136-
#[allow(unused_variables)]
137-
async_macro!(db, input: QueryMacroInput => expand_query_file(input, db))
138-
}
139-
14036
#[proc_macro]
141-
#[allow(unused_variables)]
142-
pub fn query_as(input: TokenStream) -> TokenStream {
143-
#[allow(unused_variables)]
144-
async_macro!(db, input: QueryAsMacroInput => expand_query_as(input, db, true))
145-
}
37+
pub fn expand_query(input: TokenStream) -> TokenStream {
38+
let input = syn::parse_macro_input!(input as QueryMacroInput);
14639

147-
#[proc_macro]
148-
#[allow(unused_variables)]
149-
pub fn query_file_as(input: TokenStream) -> TokenStream {
150-
async_macro!(db, input: QueryAsMacroInput => expand_query_file_as(input, db, true))
151-
}
152-
153-
#[proc_macro]
154-
#[allow(unused_variables)]
155-
pub fn query_as_unchecked(input: TokenStream) -> TokenStream {
156-
#[allow(unused_variables)]
157-
async_macro!(db, input: QueryAsMacroInput => expand_query_as(input, db, false))
158-
}
159-
160-
#[proc_macro]
161-
#[allow(unused_variables)]
162-
pub fn query_file_as_unchecked(input: TokenStream) -> TokenStream {
163-
async_macro!(db, input: QueryAsMacroInput => expand_query_file_as(input, db, false))
40+
match query_macros::expand_input(input) {
41+
Ok(ts) => ts.into(),
42+
Err(e) => {
43+
if let Some(parse_err) = e.downcast_ref::<syn::Error>() {
44+
macro_result(parse_err.to_compile_error())
45+
} else {
46+
let msg = e.to_string();
47+
macro_result(quote!(compile_error!(#msg)))
48+
}
49+
}
50+
}
16451
}
16552

16653
#[proc_macro_derive(Encode, attributes(sqlx))]

sqlx-macros/src/query_macros/args.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ use syn::Expr;
55
use quote::{quote, quote_spanned, ToTokens};
66
use sqlx::describe::Describe;
77

8+
use super::data::QueryData;
9+
use super::QueryMacroInput;
810
use crate::database::{DatabaseExt, ParamChecking};
9-
use crate::query_macros::QueryMacroInput;
1011

1112
/// Returns a tokenstream which typechecks the arguments passed to the macro
1213
/// and binds them to `DB::Arguments` with the ident `query_args`.
1314
pub fn quote_args<DB: DatabaseExt>(
1415
input: &QueryMacroInput,
15-
describe: &Describe<DB>,
16+
data: &QueryData,
1617
checked: bool,
1718
) -> crate::Result<TokenStream> {
1819
let db_path = DB::db_path();
@@ -26,23 +27,15 @@ pub fn quote_args<DB: DatabaseExt>(
2627
let arg_name = &input.arg_names;
2728

2829
let args_check = if checked && DB::PARAM_CHECKING == ParamChecking::Strong {
29-
describe
30-
.param_types
30+
data
31+
.input_types
3132
.iter()
3233
.zip(input.arg_names.iter().zip(&input.arg_exprs))
3334
.enumerate()
3435
.map(|(i, (param_ty, (name, expr)))| -> crate::Result<_> {
35-
// TODO: We could remove the ParamChecking flag and just filter to only test params that are non-null
36-
let param_ty = param_ty.as_ref().unwrap();
37-
3836
let param_ty = get_type_override(expr)
39-
.or_else(|| {
40-
Some(
41-
DB::param_type_for_id(&param_ty)?
42-
.parse::<proc_macro2::TokenStream>()
43-
.unwrap(),
44-
)
45-
})
37+
// TODO: We could remove the ParamChecking flag and just filter to only test params that are non-null
38+
.or_else(|| Some(param_ty.as_deref()?.parse().unwrap()))
4639
.ok_or_else(|| {
4740
if let Some(feature_gate) = <DB as DatabaseExt>::get_feature_gate(&param_ty) {
4841
format!(

0 commit comments

Comments
 (0)