Skip to content

Commit 21c75ba

Browse files
committed
Restore migration parameter functionality and fix tests
- Restored parameter support in migrate macro while maintaining compatibility with main branch API - Fixed test code to use SqlStr instead of Cow<String> for SQL migration content - All parameter processing tests now pass: - test_migration_process_parameters_with_substitution - test_migration_process_parameters_no_substitution - test_migration_process_parameters_missing_key - test_migration_process_parameters_missing_key_with_default_value - UI tests for parameter validation also pass - Migration functionality works with both simple path and parameter-based approaches
1 parent c13c29e commit 21c75ba

3 files changed

Lines changed: 129 additions & 12 deletions

File tree

sqlx-core/src/migrate/migration.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use sha2::{Digest, Sha384};
22
use std::borrow::Cow;
33
use std::collections::HashMap;
44

5-
use crate::sql_str::SqlStr;
5+
use crate::sql_str::{SqlStr, SqlSafeStr};
66

77
use super::{MigrateError, MigrationType};
88

@@ -85,10 +85,10 @@ impl Migration {
8585
no_tx,
8686
} = self;
8787

88-
let mut new_sql = String::with_capacity(sql.len());
88+
let mut new_sql = String::with_capacity(sql.as_str().len());
8989
let mut substitution_enabled = false;
9090

91-
for (i, line) in sql.lines().enumerate() {
91+
for (i, line) in sql.as_str().lines().enumerate() {
9292
if i != 0 {
9393
new_sql.push('\n')
9494
}
@@ -121,7 +121,7 @@ impl Migration {
121121
version: *version,
122122
description: description.clone(),
123123
migration_type: *migration_type,
124-
sql: Cow::Owned(new_sql),
124+
sql: crate::sql_str::AssertSqlSafe(new_sql).into_sql_str(),
125125
checksum: checksum.clone(),
126126
no_tx: *no_tx,
127127
})
@@ -183,7 +183,7 @@ mod test {
183183
1,
184184
Cow::Owned("test a simple parameter substitution".to_string()),
185185
crate::migrate::MigrationType::Simple,
186-
Cow::Owned(CREATE_USER.to_string()),
186+
crate::sql_str::AssertSqlSafe(CREATE_USER.to_string()).into_sql_str(),
187187
true,
188188
);
189189
let result = migration.process_parameters(&HashMap::from([(
@@ -206,7 +206,7 @@ mod test {
206206
1,
207207
std::borrow::Cow::Owned("test a simple parameter substitution".to_string()),
208208
crate::migrate::MigrationType::Simple,
209-
Cow::Owned(CREATE_TABLE.to_string()),
209+
crate::sql_str::AssertSqlSafe(CREATE_TABLE.to_string()).into_sql_str(),
210210
true,
211211
);
212212
let result = migration.process_parameters(&HashMap::from([(
@@ -233,7 +233,7 @@ mod test {
233233
1,
234234
Cow::Owned("test a simple parameter substitution".to_string()),
235235
crate::migrate::MigrationType::Simple,
236-
Cow::Owned(CREATE_TABLE.to_string()),
236+
crate::sql_str::AssertSqlSafe(CREATE_TABLE.to_string()).into_sql_str(),
237237
true,
238238
);
239239
let Err(MigrateError::MissingParameter(..)) =
@@ -269,7 +269,7 @@ mod test {
269269
1,
270270
Cow::Owned("test a simple parameter substitution".to_string()),
271271
crate::migrate::MigrationType::Simple,
272-
Cow::Owned(CREATE_TABLE.to_string()),
272+
crate::sql_str::AssertSqlSafe(CREATE_TABLE.to_string()).into_sql_str(),
273273
true,
274274
);
275275
let result = migration.process_parameters(&HashMap::with_capacity(0))?;

sqlx-macros/src/lib.rs

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,122 @@ pub fn derive_from_row(input: TokenStream) -> TokenStream {
6666
#[cfg(feature = "migrate")]
6767
#[proc_macro]
6868
pub fn migrate(input: TokenStream) -> TokenStream {
69-
use syn::{parse_macro_input, LitStr};
69+
use std::collections::HashMap;
70+
use syn::{parse_macro_input, Expr, ExprArray, ExprLit, ExprPath, ExprTuple, Lit, LitStr};
71+
use quote::quote;
7072

71-
let input = syn::parse_macro_input!(input as Option<LitStr>);
72-
match migrate::expand(input) {
73+
// Extract directory path, handling both direct literals and grouped literals
74+
fn extract_dir(expr: Option<Expr>) -> LitStr {
75+
match expr {
76+
Some(Expr::Lit(ExprLit {
77+
lit: Lit::Str(literal),
78+
..
79+
})) => return literal,
80+
Some(Expr::Group(group)) => {
81+
if let Expr::Lit(ExprLit {
82+
lit: Lit::Str(literal),
83+
..
84+
}) = *group.expr
85+
{
86+
return literal;
87+
}
88+
}
89+
_ => {}
90+
}
91+
panic!("Expected a string literal for the directory path.");
92+
}
93+
94+
// Extract a `String` value from an expression (either a string literal or a variable)
95+
fn extract_value(expr: Expr, location: &str) -> String {
96+
match expr {
97+
Expr::Lit(ExprLit {
98+
lit: Lit::Str(lit_str),
99+
..
100+
}) => lit_str.value(),
101+
Expr::Path(ExprPath { path, .. }) => path.segments.last().unwrap().ident.to_string(),
102+
_ => panic!("Expected a string literal or a variable in {location}"),
103+
}
104+
}
105+
106+
// Parse substitutions, expecting an array of tuples (String, Expr)
107+
fn parse_substitutions(expr: Option<Expr>) -> Option<HashMap<String, String>> {
108+
let Expr::Group(group) = expr? else {
109+
return None;
110+
};
111+
let Expr::Array(ExprArray { elems, .. }) = *group.expr else {
112+
panic!("Expected an array of tuples (String, Expr).");
113+
};
114+
115+
let mut map = HashMap::new();
116+
for elem in elems {
117+
let Expr::Tuple(ExprTuple {
118+
elems: tuple_elems, ..
119+
}) = elem
120+
else {
121+
panic!("Expected a tuple (String, Expr). Got {:#?}", elem);
122+
};
123+
124+
let mut tuple_elems = tuple_elems.into_iter();
125+
126+
let key = extract_value(tuple_elems.next().expect("Missing key in tuple."), "key");
127+
let value = extract_value(
128+
tuple_elems.next().expect("Missing value in tuple."),
129+
"value",
130+
);
131+
map.insert(key, value);
132+
}
133+
Some(map)
134+
}
135+
136+
// Handle both the simple case (just path) and the tuple case (path + parameters)
137+
let input_result: std::result::Result<Option<LitStr>, syn::Error> = syn::parse(input.clone());
138+
if let Ok(simple_input) = input_result {
139+
// Simple case: just a path or no arguments
140+
return match migrate::expand(simple_input) {
141+
Ok(ts) => ts.into(),
142+
Err(e) => {
143+
if let Some(parse_err) = e.downcast_ref::<syn::Error>() {
144+
parse_err.to_compile_error().into()
145+
} else {
146+
let msg = e.to_string();
147+
quote!(::std::compile_error!(#msg)).into()
148+
}
149+
}
150+
};
151+
}
152+
153+
// Complex case: parse tuple with parameters
154+
let exp = parse_macro_input!(input as syn::Expr);
155+
let (dir, parameters) = match exp {
156+
Expr::Tuple(ExprTuple { elems, .. }) => {
157+
let mut elems = elems.into_iter();
158+
(extract_dir(elems.next()), elems.next())
159+
}
160+
Expr::Lit(ExprLit {
161+
lit: Lit::Str(lit_str),
162+
..
163+
}) => {
164+
(lit_str, None)
165+
}
166+
Expr::Group(group) => {
167+
if let Expr::Lit(ExprLit {
168+
lit: Lit::Str(lit_str),
169+
..
170+
}) = *group.expr
171+
{
172+
(lit_str, None)
173+
} else {
174+
panic!("Expected a tuple with directory path and optional parameters, or a string literal for the directory path.");
175+
}
176+
},
177+
_ => panic!(
178+
"Expected a tuple with directory path and optional parameters, or a string literal for the directory path."
179+
),
180+
};
181+
182+
// Parse substitutions and pass to migration expander
183+
let substitutions = parse_substitutions(parameters);
184+
match migrate::expand_migrator_from_lit_dir(dir, substitutions) {
73185
Ok(ts) => ts.into(),
74186
Err(e) => {
75187
if let Some(parse_err) = e.downcast_ref::<syn::Error>() {

src/macros/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,10 +861,15 @@ macro_rules! query_file_scalar_unchecked (
861861
#[cfg(feature = "migrate")]
862862
#[macro_export]
863863
macro_rules! migrate {
864+
($directory:literal, parameters = $parameters:expr) => {
865+
$crate::sqlx_macros::migrate!(($directory, $parameters))
866+
};
867+
(parameters = $parameters:expr) => {
868+
$crate::sqlx_macros::migrate!(("./migrations", $parameters))
869+
};
864870
($dir:literal) => {{
865871
$crate::sqlx_macros::migrate!($dir)
866872
}};
867-
868873
() => {{
869874
$crate::sqlx_macros::migrate!()
870875
}};

0 commit comments

Comments
 (0)