feat: make macros aware of macros.preferred-crates

This commit is contained in:
Austin Bonander
2024-09-19 22:54:48 -07:00
parent 8604b51ae3
commit 13f6ef0ab0
24 changed files with 814 additions and 378 deletions

View File

@@ -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))]

View File

@@ -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),
}))
}

View File

@@ -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(),}),
})
}
}

View File

@@ -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>],
},
},
);