Skip to content

Commit 732233a

Browse files
committed
fix: only warn on ambiguous crates if the invocation relies on it
1 parent 4e95baf commit 732233a

File tree

4 files changed

+130
-20
lines changed

4 files changed

+130
-20
lines changed

sqlx-core/src/type_checking.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ pub enum Error {
6060
DateTimeCrateFeatureNotEnabled,
6161
#[error("Cargo feature for configured `macros.preferred-crates.numeric` not enabled")]
6262
NumericCrateFeatureNotEnabled,
63+
#[error("multiple date-time types are possible; falling back to `{fallback}`")]
64+
AmbiguousDateTimeType { fallback: &'static str },
65+
#[error("multiple numeric types are possible; falling back to `{fallback}`")]
66+
AmbiguousNumericType { fallback: &'static str },
6367
}
6468

6569
/// An adapter for [`Value`] which attempts to decode the value and format it when printed using [`Debug`].
@@ -195,12 +199,24 @@ macro_rules! impl_type_checking {
195199
if matches!(preferred_crates.date_time, DateTimeCrate::Time | DateTimeCrate::Inferred) {
196200
$(
197201
if <$time_ty as sqlx_core::types::Type<$database>>::type_info() == *info {
202+
if cfg!(feature = "chrono") {
203+
return Err($crate::type_checking::Error::AmbiguousDateTimeType {
204+
fallback: $crate::select_input_type!($time_ty $(, $time_input)?),
205+
});
206+
}
207+
198208
return Ok($crate::select_input_type!($time_ty $(, $time_input)?));
199209
}
200210
)*
201211

202212
$(
203213
if <$time_ty as sqlx_core::types::Type<$database>>::compatible(info) {
214+
if cfg!(feature = "chrono") {
215+
return Err($crate::type_checking::Error::AmbiguousDateTimeType {
216+
fallback: $crate::select_input_type!($time_ty $(, $time_input)?),
217+
});
218+
}
219+
204220
return Ok($crate::select_input_type!($time_ty $(, $time_input)?));
205221
}
206222
)*
@@ -240,12 +256,24 @@ macro_rules! impl_type_checking {
240256
if matches!(preferred_crates.numeric, NumericCrate::BigDecimal | NumericCrate::Inferred) {
241257
$(
242258
if <$bigdecimal_ty as sqlx_core::types::Type<$database>>::type_info() == *info {
259+
if cfg!(feature = "rust_decimal") {
260+
return Err($crate::type_checking::Error::AmbiguousNumericType {
261+
fallback: $crate::select_input_type!($bigdecimal_ty $(, $bigdecimal_input)?),
262+
});
263+
}
264+
243265
return Ok($crate::select_input_type!($bigdecimal_ty $(, $bigdecimal_input)?));
244266
}
245267
)*
246268

247269
$(
248270
if <$bigdecimal_ty as sqlx_core::types::Type<$database>>::compatible(info) {
271+
if cfg!(feature = "rust_decimal") {
272+
return Err($crate::type_checking::Error::AmbiguousNumericType {
273+
fallback: $crate::select_input_type!($bigdecimal_ty $(, $bigdecimal_input)?),
274+
});
275+
}
276+
249277
return Ok($crate::select_input_type!($bigdecimal_ty $(, $bigdecimal_input)?));
250278
}
251279
)*
@@ -311,12 +339,24 @@ macro_rules! impl_type_checking {
311339
if matches!(preferred_crates.date_time, DateTimeCrate::Time | DateTimeCrate::Inferred) {
312340
$(
313341
if <$time_ty as sqlx_core::types::Type<$database>>::type_info() == *info {
342+
if cfg!(feature = "chrono") {
343+
return Err($crate::type_checking::Error::AmbiguousDateTimeType {
344+
fallback: stringify!($time_ty),
345+
});
346+
}
347+
314348
return Ok(stringify!($time_ty));
315349
}
316350
)*
317351

318352
$(
319353
if <$time_ty as sqlx_core::types::Type<$database>>::compatible(info) {
354+
if cfg!(feature = "chrono") {
355+
return Err($crate::type_checking::Error::AmbiguousDateTimeType {
356+
fallback: stringify!($time_ty),
357+
});
358+
}
359+
320360
return Ok(stringify!($time_ty));
321361
}
322362
)*
@@ -356,12 +396,24 @@ macro_rules! impl_type_checking {
356396
if matches!(preferred_crates.numeric, NumericCrate::BigDecimal | NumericCrate::Inferred) {
357397
$(
358398
if <$bigdecimal_ty as sqlx_core::types::Type<$database>>::type_info() == *info {
399+
if cfg!(feature = "rust_decimal") {
400+
return Err($crate::type_checking::Error::AmbiguousDateTimeType {
401+
fallback: stringify!($bigdecimal_ty),
402+
});
403+
}
404+
359405
return Ok(stringify!($bigdecimal_ty));
360406
}
361407
)*
362408

363409
$(
364410
if <$bigdecimal_ty as sqlx_core::types::Type<$database>>::compatible(info) {
411+
if cfg!(feature = "rust_decimal") {
412+
return Err($crate::type_checking::Error::AmbiguousDateTimeType {
413+
fallback: stringify!($bigdecimal_ty),
414+
});
415+
}
416+
365417
return Ok(stringify!($bigdecimal_ty));
366418
}
367419
)*
@@ -438,6 +490,24 @@ macro_rules! impl_type_checking {
438490
)*
439491
}
440492

493+
#[cfg(feature = "bigdecimal")]
494+
{
495+
$(
496+
if <$bigdecimal_ty as sqlx_core::types::Type<$database>>::compatible(&info) {
497+
return $crate::type_checking::FmtValue::debug::<$bigdecimal_ty>(value);
498+
}
499+
)*
500+
}
501+
502+
#[cfg(feature = "rust_decimal")]
503+
{
504+
$(
505+
if <$rust_decimal_ty as sqlx_core::types::Type<$database>>::compatible(&info) {
506+
return $crate::type_checking::FmtValue::debug::<$rust_decimal_ty>(value);
507+
}
508+
)*
509+
}
510+
441511
$(
442512
$(#[$meta])?
443513
if <$ty as sqlx_core::types::Type<$database>>::compatible(&info) {

sqlx-macros-core/src/query/args.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use crate::database::DatabaseExt;
2-
use crate::query::QueryMacroInput;
2+
use crate::query::{QueryMacroInput, Warnings};
33
use either::Either;
44
use proc_macro2::TokenStream;
55
use quote::{format_ident, quote, quote_spanned};
66
use sqlx_core::config::Config;
77
use sqlx_core::describe::Describe;
88
use sqlx_core::type_checking;
9+
use sqlx_core::type_checking::Error;
910
use sqlx_core::type_info::TypeInfo;
1011
use syn::spanned::Spanned;
1112
use syn::{Expr, ExprCast, ExprGroup, Type};
@@ -15,6 +16,7 @@ use syn::{Expr, ExprCast, ExprGroup, Type};
1516
pub fn quote_args<DB: DatabaseExt>(
1617
input: &QueryMacroInput,
1718
config: &Config,
19+
warnings: &mut Warnings,
1820
info: &Describe<DB>,
1921
) -> crate::Result<TokenStream> {
2022
let db_path = DB::db_path();
@@ -59,7 +61,7 @@ pub fn quote_args<DB: DatabaseExt>(
5961
return Ok(quote!());
6062
}
6163

62-
let param_ty = get_param_type::<DB>(param_ty, config, i)?;
64+
let param_ty = get_param_type::<DB>(param_ty, config, warnings, i)?;
6365

6466
Ok(quote_spanned!(expr.span() =>
6567
// this shouldn't actually run
@@ -107,6 +109,7 @@ pub fn quote_args<DB: DatabaseExt>(
107109
fn get_param_type<DB: DatabaseExt>(
108110
param_ty: &DB::TypeInfo,
109111
config: &Config,
112+
warnings: &mut Warnings,
110113
i: usize,
111114
) -> crate::Result<TokenStream> {
112115
if let Some(type_override) = config.macros.type_override(param_ty.name()) {
@@ -156,6 +159,15 @@ fn get_param_type<DB: DatabaseExt>(
156159
(configured by `macros.preferred-crates.numeric` in sqlx.toml)",
157160
)
158161
}
162+
163+
Error::AmbiguousDateTimeType { fallback } => {
164+
warnings.ambiguous_datetime = true;
165+
return Ok(fallback.parse()?);
166+
}
167+
Error::AmbiguousNumericType { fallback } => {
168+
warnings.ambiguous_numeric = true;
169+
return Ok(fallback.parse()?);
170+
}
159171
};
160172

161173
Err(message.into())

sqlx-macros-core/src/query/mod.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,12 @@ impl<DB: Database> DescribeExt for Describe<DB> where
241241
{
242242
}
243243

244+
#[derive(Default)]
245+
struct Warnings {
246+
ambiguous_datetime: bool,
247+
ambiguous_numeric: bool,
248+
}
249+
244250
fn expand_with_data<DB: DatabaseExt>(
245251
input: QueryMacroInput,
246252
data: QueryData<DB>,
@@ -267,7 +273,9 @@ where
267273
}
268274
}
269275

270-
let args_tokens = args::quote_args(&input, config, &data.describe)?;
276+
let mut warnings = Warnings::default();
277+
278+
let args_tokens = args::quote_args(&input, config, &mut warnings, &data.describe)?;
271279

272280
let query_args = format_ident!("query_args");
273281

@@ -286,7 +294,7 @@ where
286294
} else {
287295
match input.record_type {
288296
RecordType::Generated => {
289-
let columns = output::columns_to_rust::<DB>(&data.describe, config)?;
297+
let columns = output::columns_to_rust::<DB>(&data.describe, config, &mut warnings)?;
290298

291299
let record_name: Type = syn::parse_str("Record").unwrap();
292300

@@ -322,28 +330,32 @@ where
322330
record_tokens
323331
}
324332
RecordType::Given(ref out_ty) => {
325-
let columns = output::columns_to_rust::<DB>(&data.describe, config)?;
333+
let columns = output::columns_to_rust::<DB>(&data.describe, config, &mut warnings)?;
326334

327335
output::quote_query_as::<DB>(&input, out_ty, &query_args, &columns)
328336
}
329-
RecordType::Scalar => {
330-
output::quote_query_scalar::<DB>(&input, config, &query_args, &data.describe)?
331-
}
337+
RecordType::Scalar => output::quote_query_scalar::<DB>(
338+
&input,
339+
config,
340+
&mut warnings,
341+
&query_args,
342+
&data.describe,
343+
)?,
332344
}
333345
};
334346

335-
let mut warnings = TokenStream::new();
347+
let mut warnings_out = TokenStream::new();
336348

337-
if config.macros.preferred_crates.date_time.is_inferred() {
349+
if warnings.ambiguous_datetime {
338350
// Warns if the date-time crate is inferred but both `chrono` and `time` are enabled
339-
warnings.extend(quote! {
351+
warnings_out.extend(quote! {
340352
::sqlx::warn_on_ambiguous_inferred_date_time_crate();
341353
});
342354
}
343355

344-
if config.macros.preferred_crates.numeric.is_inferred() {
356+
if warnings.ambiguous_numeric {
345357
// Warns if the numeric crate is inferred but both `bigdecimal` and `rust_decimal` are enabled
346-
warnings.extend(quote! {
358+
warnings_out.extend(quote! {
347359
::sqlx::warn_on_ambiguous_inferred_numeric_crate();
348360
});
349361
}
@@ -354,7 +366,7 @@ where
354366
{
355367
use ::sqlx::Arguments as _;
356368

357-
#warnings
369+
#warnings_out
358370

359371
#args_tokens
360372

sqlx-macros-core/src/query/output.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use sqlx_core::describe::Describe;
77

88
use crate::database::DatabaseExt;
99

10-
use crate::query::QueryMacroInput;
10+
use crate::query::{QueryMacroInput, Warnings};
1111
use sqlx_core::config::Config;
1212
use sqlx_core::type_checking;
1313
use sqlx_core::type_checking::TypeChecking;
@@ -82,15 +82,17 @@ impl Display for DisplayColumn<'_> {
8282
pub fn columns_to_rust<DB: DatabaseExt>(
8383
describe: &Describe<DB>,
8484
config: &Config,
85+
warnings: &mut Warnings,
8586
) -> crate::Result<Vec<RustColumn>> {
8687
(0..describe.columns().len())
87-
.map(|i| column_to_rust(describe, config, i))
88+
.map(|i| column_to_rust(describe, config, warnings, i))
8889
.collect::<crate::Result<Vec<_>>>()
8990
}
9091

9192
fn column_to_rust<DB: DatabaseExt>(
9293
describe: &Describe<DB>,
9394
config: &Config,
95+
warnings: &mut Warnings,
9496
i: usize,
9597
) -> crate::Result<RustColumn> {
9698
let column = &describe.columns()[i];
@@ -116,7 +118,7 @@ fn column_to_rust<DB: DatabaseExt>(
116118
(ColumnTypeOverride::Wildcard, true) => ColumnType::OptWildcard,
117119

118120
(ColumnTypeOverride::None, _) => {
119-
let type_ = get_column_type::<DB>(config, i, column);
121+
let type_ = get_column_type::<DB>(config, warnings, i, column);
120122
if !nullable {
121123
ColumnType::Exact(type_)
122124
} else {
@@ -204,6 +206,7 @@ pub fn quote_query_as<DB: DatabaseExt>(
204206
pub fn quote_query_scalar<DB: DatabaseExt>(
205207
input: &QueryMacroInput,
206208
config: &Config,
209+
warnings: &mut Warnings,
207210
bind_args: &Ident,
208211
describe: &Describe<DB>,
209212
) -> crate::Result<TokenStream> {
@@ -218,10 +221,10 @@ pub fn quote_query_scalar<DB: DatabaseExt>(
218221
}
219222

220223
// attempt to parse a column override, otherwise fall back to the inferred type of the column
221-
let ty = if let Ok(rust_col) = column_to_rust(describe, config, 0) {
224+
let ty = if let Ok(rust_col) = column_to_rust(describe, config, warnings, 0) {
222225
rust_col.type_.to_token_stream()
223226
} else if input.checked {
224-
let ty = get_column_type::<DB>(config, 0, &columns[0]);
227+
let ty = get_column_type::<DB>(config, warnings, 0, &columns[0]);
225228
if describe.nullable(0).unwrap_or(true) {
226229
quote! { ::std::option::Option<#ty> }
227230
} else {
@@ -239,7 +242,12 @@ pub fn quote_query_scalar<DB: DatabaseExt>(
239242
})
240243
}
241244

242-
fn get_column_type<DB: DatabaseExt>(config: &Config, i: usize, column: &DB::Column) -> TokenStream {
245+
fn get_column_type<DB: DatabaseExt>(
246+
config: &Config,
247+
warnings: &mut Warnings,
248+
i: usize,
249+
column: &DB::Column,
250+
) -> TokenStream {
243251
if let ColumnOrigin::Table(origin) = column.origin() {
244252
if let Some(column_override) = config.macros.column_override(&origin.table, &origin.name) {
245253
return column_override.parse().unwrap();
@@ -322,6 +330,14 @@ fn get_column_type<DB: DatabaseExt>(config: &Config, i: usize, column: &DB::Colu
322330
}
323331
)
324332
}
333+
type_checking::Error::AmbiguousDateTimeType { fallback } => {
334+
warnings.ambiguous_datetime = true;
335+
return fallback.parse().unwrap();
336+
}
337+
type_checking::Error::AmbiguousNumericType { fallback } => {
338+
warnings.ambiguous_numeric = true;
339+
return fallback.parse().unwrap();
340+
}
325341
};
326342

327343
syn::Error::new(Span::call_site(), message).to_compile_error()

0 commit comments

Comments
 (0)