mirror of
https://github.com/launchbadge/sqlx.git
synced 2026-03-20 00:54:18 +00:00
feat: make macros aware of macros.preferred-crates
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
use crate::ext::ustr::UStr;
|
||||
use crate::{PgTypeInfo, Postgres};
|
||||
|
||||
pub(crate) use sqlx_core::column::{Column, ColumnIndex};
|
||||
use sqlx_core::column::ColumnOrigin;
|
||||
pub(crate) use sqlx_core::column::{Column, ColumnIndex};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
|
||||
@@ -13,7 +13,7 @@ pub struct PgColumn {
|
||||
|
||||
#[cfg_attr(feature = "offline", serde(default))]
|
||||
pub(crate) origin: ColumnOrigin,
|
||||
|
||||
|
||||
#[cfg_attr(feature = "offline", serde(skip))]
|
||||
pub(crate) relation_id: Option<crate::types::Oid>,
|
||||
#[cfg_attr(feature = "offline", serde(skip))]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::btree_map;
|
||||
use crate::connection::TableColumns;
|
||||
use crate::error::Error;
|
||||
use crate::ext::ustr::UStr;
|
||||
use crate::io::StatementId;
|
||||
@@ -12,11 +12,9 @@ use crate::types::Oid;
|
||||
use crate::HashMap;
|
||||
use crate::{PgColumn, PgConnection, PgTypeInfo};
|
||||
use smallvec::SmallVec;
|
||||
use sqlx_core::column::{ColumnOrigin, TableColumn};
|
||||
use sqlx_core::query_builder::QueryBuilder;
|
||||
use std::sync::Arc;
|
||||
use sqlx_core::column::{ColumnOrigin, TableColumn};
|
||||
use sqlx_core::hash_map;
|
||||
use crate::connection::TableColumns;
|
||||
|
||||
/// Describes the type of the `pg_type.typtype` column
|
||||
///
|
||||
@@ -125,9 +123,12 @@ impl PgConnection {
|
||||
let type_info = self
|
||||
.maybe_fetch_type_info_by_oid(field.data_type_id, should_fetch)
|
||||
.await?;
|
||||
|
||||
let origin = if let (Some(relation_oid), Some(attribute_no)) = (field.relation_id, field.relation_attribute_no) {
|
||||
self.maybe_fetch_column_origin(relation_oid, attribute_no, should_fetch).await?
|
||||
|
||||
let origin = if let (Some(relation_oid), Some(attribute_no)) =
|
||||
(field.relation_id, field.relation_attribute_no)
|
||||
{
|
||||
self.maybe_fetch_column_origin(relation_oid, attribute_no, should_fetch)
|
||||
.await?
|
||||
} else {
|
||||
ColumnOrigin::Expression
|
||||
};
|
||||
@@ -200,52 +201,65 @@ impl PgConnection {
|
||||
Ok(PgTypeInfo(PgType::DeclareWithOid(oid)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn maybe_fetch_column_origin(
|
||||
&mut self,
|
||||
relation_id: Oid,
|
||||
&mut self,
|
||||
relation_id: Oid,
|
||||
attribute_no: i16,
|
||||
should_fetch: bool,
|
||||
) -> Result<ColumnOrigin, Error> {
|
||||
let mut table_columns = match self.cache_table_to_column_names.entry(relation_id) {
|
||||
hash_map::Entry::Occupied(table_columns) => {
|
||||
table_columns.into_mut()
|
||||
},
|
||||
hash_map::Entry::Vacant(vacant) => {
|
||||
if !should_fetch { return Ok(ColumnOrigin::Unknown); }
|
||||
|
||||
let table_name: String = query_scalar("SELECT $1::oid::regclass::text")
|
||||
.bind(relation_id)
|
||||
.fetch_one(&mut *self)
|
||||
.await?;
|
||||
|
||||
vacant.insert(TableColumns {
|
||||
table_name: table_name.into(),
|
||||
columns: Default::default(),
|
||||
if let Some(origin) =
|
||||
self.cache_table_to_column_names
|
||||
.get(&relation_id)
|
||||
.and_then(|table_columns| {
|
||||
let column_name = table_columns.columns.get(&attribute_no).cloned()?;
|
||||
|
||||
Some(ColumnOrigin::Table(TableColumn {
|
||||
table: table_columns.table_name.clone(),
|
||||
name: column_name,
|
||||
}))
|
||||
})
|
||||
}
|
||||
{
|
||||
return Ok(origin);
|
||||
}
|
||||
|
||||
if !should_fetch {
|
||||
return Ok(ColumnOrigin::Unknown);
|
||||
}
|
||||
|
||||
// Looking up the table name _may_ end up being redundant,
|
||||
// but the round-trip to the server is by far the most expensive part anyway.
|
||||
let Some((table_name, column_name)): Option<(String, String)> = query_as(
|
||||
// language=PostgreSQL
|
||||
"SELECT $1::oid::regclass::text, attname \
|
||||
FROM pg_catalog.pg_attribute \
|
||||
WHERE attrelid = $1 AND attnum = $2",
|
||||
)
|
||||
.bind(relation_id)
|
||||
.bind(attribute_no)
|
||||
.fetch_optional(&mut *self)
|
||||
.await?
|
||||
else {
|
||||
// The column/table doesn't exist anymore for whatever reason.
|
||||
return Ok(ColumnOrigin::Unknown);
|
||||
};
|
||||
|
||||
let column_name = match table_columns.columns.entry(attribute_no) {
|
||||
btree_map::Entry::Occupied(occupied) => Arc::clone(occupied.get()),
|
||||
btree_map::Entry::Vacant(vacant) => {
|
||||
if !should_fetch { return Ok(ColumnOrigin::Unknown); }
|
||||
|
||||
let column_name: String = query_scalar(
|
||||
"SELECT attname FROM pg_attribute WHERE attrelid = $1 AND attnum = $2"
|
||||
)
|
||||
.bind(relation_id)
|
||||
.bind(attribute_no)
|
||||
.fetch_one(&mut *self)
|
||||
.await?;
|
||||
|
||||
Arc::clone(vacant.insert(column_name.into()))
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let table_columns = self
|
||||
.cache_table_to_column_names
|
||||
.entry(relation_id)
|
||||
.or_insert_with(|| TableColumns {
|
||||
table_name: table_name.into(),
|
||||
columns: Default::default(),
|
||||
});
|
||||
|
||||
let column_name = table_columns
|
||||
.columns
|
||||
.entry(attribute_no)
|
||||
.or_insert(column_name.into());
|
||||
|
||||
Ok(ColumnOrigin::Table(TableColumn {
|
||||
table: table_columns.table_name.clone(),
|
||||
name: column_name
|
||||
name: Arc::clone(column_name),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -148,8 +148,8 @@ impl PgConnection {
|
||||
cache_type_oid: HashMap::new(),
|
||||
cache_type_info: HashMap::new(),
|
||||
cache_elem_type_to_array: HashMap::new(),
|
||||
log_settings: options.log_settings.clone(),
|
||||
}),
|
||||
cache_table_to_column_names: HashMap::new(),
|
||||
log_settings: options.log_settings.clone(),}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,42 +39,6 @@ impl_type_checking!(
|
||||
#[cfg(feature = "uuid")]
|
||||
sqlx::types::Uuid,
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
sqlx::types::chrono::NaiveTime,
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
sqlx::types::chrono::NaiveDate,
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
sqlx::types::chrono::NaiveDateTime,
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc> | sqlx::types::chrono::DateTime<_>,
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
sqlx::postgres::types::PgTimeTz<sqlx::types::chrono::NaiveTime, sqlx::types::chrono::FixedOffset>,
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
sqlx::types::time::Time,
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
sqlx::types::time::Date,
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
sqlx::types::time::PrimitiveDateTime,
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
sqlx::types::time::OffsetDateTime,
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
sqlx::postgres::types::PgTimeTz<sqlx::types::time::Time, sqlx::types::time::UtcOffset>,
|
||||
|
||||
#[cfg(feature = "bigdecimal")]
|
||||
sqlx::types::BigDecimal,
|
||||
|
||||
#[cfg(feature = "rust_decimal")]
|
||||
sqlx::types::Decimal,
|
||||
|
||||
#[cfg(feature = "ipnetwork")]
|
||||
sqlx::types::ipnetwork::IpNetwork,
|
||||
|
||||
@@ -106,36 +70,6 @@ impl_type_checking!(
|
||||
#[cfg(feature = "uuid")]
|
||||
Vec<sqlx::types::Uuid> | &[sqlx::types::Uuid],
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
Vec<sqlx::types::chrono::NaiveTime> | &[sqlx::types::chrono::NaiveTime],
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
Vec<sqlx::types::chrono::NaiveDate> | &[sqlx::types::chrono::NaiveDate],
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
Vec<sqlx::types::chrono::NaiveDateTime> | &[sqlx::types::chrono::NaiveDateTime],
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
Vec<sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>> | &[sqlx::types::chrono::DateTime<_>],
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
Vec<sqlx::types::time::Time> | &[sqlx::types::time::Time],
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
Vec<sqlx::types::time::Date> | &[sqlx::types::time::Date],
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
Vec<sqlx::types::time::PrimitiveDateTime> | &[sqlx::types::time::PrimitiveDateTime],
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
Vec<sqlx::types::time::OffsetDateTime> | &[sqlx::types::time::OffsetDateTime],
|
||||
|
||||
#[cfg(feature = "bigdecimal")]
|
||||
Vec<sqlx::types::BigDecimal> | &[sqlx::types::BigDecimal],
|
||||
|
||||
#[cfg(feature = "rust_decimal")]
|
||||
Vec<sqlx::types::Decimal> | &[sqlx::types::Decimal],
|
||||
|
||||
#[cfg(feature = "ipnetwork")]
|
||||
Vec<sqlx::types::ipnetwork::IpNetwork> | &[sqlx::types::ipnetwork::IpNetwork],
|
||||
|
||||
@@ -152,72 +86,114 @@ impl_type_checking!(
|
||||
sqlx::postgres::types::PgRange<i32>,
|
||||
sqlx::postgres::types::PgRange<i64>,
|
||||
|
||||
#[cfg(feature = "bigdecimal")]
|
||||
sqlx::postgres::types::PgRange<sqlx::types::BigDecimal>,
|
||||
|
||||
#[cfg(feature = "rust_decimal")]
|
||||
sqlx::postgres::types::PgRange<sqlx::types::Decimal>,
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDate>,
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDateTime>,
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>> |
|
||||
sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<_>>,
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
sqlx::postgres::types::PgRange<sqlx::types::time::Date>,
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
sqlx::postgres::types::PgRange<sqlx::types::time::PrimitiveDateTime>,
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
sqlx::postgres::types::PgRange<sqlx::types::time::OffsetDateTime>,
|
||||
|
||||
// Range arrays
|
||||
|
||||
Vec<sqlx::postgres::types::PgRange<i32>> | &[sqlx::postgres::types::PgRange<i32>],
|
||||
Vec<sqlx::postgres::types::PgRange<i64>> | &[sqlx::postgres::types::PgRange<i64>],
|
||||
|
||||
#[cfg(feature = "bigdecimal")]
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::BigDecimal>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::BigDecimal>],
|
||||
|
||||
#[cfg(feature = "rust_decimal")]
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::Decimal>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::Decimal>],
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDate>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDate>],
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDateTime>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDateTime>],
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<_>>],
|
||||
|
||||
#[cfg(all(feature = "chrono", not(feature = "time")))]
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<_>>],
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::time::Date>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::time::Date>],
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::time::PrimitiveDateTime>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::time::PrimitiveDateTime>],
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::time::OffsetDateTime>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::time::OffsetDateTime>],
|
||||
},
|
||||
ParamChecking::Strong,
|
||||
feature-types: info => info.__type_feature_gate(),
|
||||
// The expansion of the macro automatically applies the correct feature name
|
||||
// and checks `[macros.preferred-crates]`
|
||||
datetime-types: {
|
||||
chrono: {
|
||||
// Scalar types
|
||||
sqlx::types::chrono::NaiveTime,
|
||||
|
||||
sqlx::types::chrono::NaiveDate,
|
||||
|
||||
sqlx::types::chrono::NaiveDateTime,
|
||||
|
||||
sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc> | sqlx::types::chrono::DateTime<_>,
|
||||
|
||||
sqlx::postgres::types::PgTimeTz<sqlx::types::chrono::NaiveTime, sqlx::types::chrono::FixedOffset>,
|
||||
|
||||
// Array types
|
||||
Vec<sqlx::types::chrono::NaiveTime> | &[sqlx::types::chrono::NaiveTime],
|
||||
|
||||
Vec<sqlx::types::chrono::NaiveDate> | &[sqlx::types::chrono::NaiveDate],
|
||||
|
||||
Vec<sqlx::types::chrono::NaiveDateTime> | &[sqlx::types::chrono::NaiveDateTime],
|
||||
|
||||
Vec<sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>> | &[sqlx::types::chrono::DateTime<_>],
|
||||
|
||||
// Range types
|
||||
sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDate>,
|
||||
|
||||
sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDateTime>,
|
||||
|
||||
sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>> |
|
||||
sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<_>>,
|
||||
|
||||
// Arrays of ranges
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDate>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDate>],
|
||||
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDateTime>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDateTime>],
|
||||
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<_>>],
|
||||
},
|
||||
time: {
|
||||
// Scalar types
|
||||
sqlx::types::time::Time,
|
||||
|
||||
sqlx::types::time::Date,
|
||||
|
||||
sqlx::types::time::PrimitiveDateTime,
|
||||
|
||||
sqlx::types::time::OffsetDateTime,
|
||||
|
||||
sqlx::postgres::types::PgTimeTz<sqlx::types::time::Time, sqlx::types::time::UtcOffset>,
|
||||
|
||||
// Array types
|
||||
Vec<sqlx::types::time::Time> | &[sqlx::types::time::Time],
|
||||
|
||||
Vec<sqlx::types::time::Date> | &[sqlx::types::time::Date],
|
||||
|
||||
Vec<sqlx::types::time::PrimitiveDateTime> | &[sqlx::types::time::PrimitiveDateTime],
|
||||
|
||||
Vec<sqlx::types::time::OffsetDateTime> | &[sqlx::types::time::OffsetDateTime],
|
||||
|
||||
// Range types
|
||||
sqlx::postgres::types::PgRange<sqlx::types::time::Date>,
|
||||
|
||||
sqlx::postgres::types::PgRange<sqlx::types::time::PrimitiveDateTime>,
|
||||
|
||||
sqlx::postgres::types::PgRange<sqlx::types::time::OffsetDateTime>,
|
||||
|
||||
// Arrays of ranges
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::time::Date>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::time::Date>],
|
||||
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::time::PrimitiveDateTime>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::time::PrimitiveDateTime>],
|
||||
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::time::OffsetDateTime>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::time::OffsetDateTime>],
|
||||
},
|
||||
},
|
||||
numeric-types: {
|
||||
bigdecimal: {
|
||||
sqlx::types::BigDecimal,
|
||||
|
||||
Vec<sqlx::types::BigDecimal> | &[sqlx::types::BigDecimal],
|
||||
|
||||
sqlx::postgres::types::PgRange<sqlx::types::BigDecimal>,
|
||||
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::BigDecimal>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::BigDecimal>],
|
||||
},
|
||||
rust_decimal: {
|
||||
sqlx::types::Decimal,
|
||||
|
||||
Vec<sqlx::types::Decimal> | &[sqlx::types::Decimal],
|
||||
|
||||
sqlx::postgres::types::PgRange<sqlx::types::Decimal>,
|
||||
|
||||
Vec<sqlx::postgres::types::PgRange<sqlx::types::Decimal>> |
|
||||
&[sqlx::postgres::types::PgRange<sqlx::types::Decimal>],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user