doc(macros): document type override feature for macros

This commit is contained in:
Austin Bonander 2020-06-11 20:56:37 -07:00 committed by Ryan Leckey
parent 7b37ebde0f
commit 897c8f429a

View File

@ -1,6 +1,6 @@
/// Statically checked SQL query with `println!()` style syntax.
///
/// This expands to an instance of [QueryAs] that outputs an ad-hoc anonymous struct type,
/// This expands to an instance of [QueryAs][crate::QueryAs] that outputs an ad-hoc anonymous struct type,
/// if the query has output columns, or `()` (unit) otherwise:
///
/// ```rust,ignore
@ -111,9 +111,78 @@
/// `NULL` which then depends on the semantics of what functions are used. Consult the MySQL
/// manual for the functions you are using to find the cases in which they return `NULL`.
///
/// To override the nullability of an output column, use [query_as!].
/// To override the nullability of an output column, use [query_as!], or see below.
///
/// ### Offline Mode (requires the `offline` feature)
/// ## Type Overrides: Bind Parameters (Postgres only)
/// For typechecking of bind parameters, casts using `as` are treated as overrides for the inferred
/// types of bind parameters and no typechecking is emitted:
///
/// ```rust,ignore
/// #[derive(sqlx::Type)]
/// #[sqlx(transparent)]
/// struct MyInt4(i32);
///
/// let my_int = MyInt4(1);
///
/// sqlx::query!("select $1::int4 as id", my_int as MyInt4)
/// ```
///
/// In Rust 1.45 we can eliminate this redundancy by allowing casts using `as _` or type ascription
/// syntax, i.e. `my_int: _` (which is unstable but can be stripped), but this requires modifying
/// the expression which is not possible as the macros are currently implemented. Casts to `_` are
/// forbidden for now as they produce rather nasty type errors.
///
/// ## Type Overrides: Output Columns
/// Type overrides are also available for output columns, utilizing the SQL standard's support
/// for arbitrary text in column names:
///
/// * selecting a column `foo as "foo!"` (Postgres / SQLite) or `` foo as `foo!` `` overrides
/// inferred nullability and forces the column to be treated as `NOT NULL`; this is useful e.g. for
/// selecting expressions in Postgres where we cannot infer nullability:
///
/// ```rust,ignore
/// # async fn main() {
/// # let mut conn = panic!();
/// // Postgres: using a raw query string lets us use unescaped double-quotes
/// // Note that this query wouldn't work in SQLite as we still don't know the exact type of `id`
/// let record = sqlx::query!(r#"select 1 as "id!""#) // MySQL: use "select 1 as `id!`" instead
/// .fetch_one(&mut conn)
/// .await?;
///
/// // For Postgres this would have been inferred to be Option<i32> instead
/// assert_eq!(record.id, 1i32);
/// # }
/// ```
///
/// * selecting a column `foo as "foo: T"` (Postgres / SQLite) or `` foo as `foo: T` `` (MySQL)
/// overrides the inferred type which is useful when selecting user-defined custom types
/// (dynamic type checking is still done so if the types are incompatible this will be an error
/// at runtime instead of compile-time):
///
/// ```rust,ignore
/// # async fn main() {
/// # let mut conn = panic!();
/// #[derive(sqlx::Type)]
/// #[sqlx(transparent)
/// struct MyInt4(i32);
///
/// let my_int = MyInt4(1);
///
/// // Postgres/SQLite
/// sqlx::query!(r#"select 1 as "id: MyInt4""#) // MySQL: use "select 1 as `id: MyInt4`" instead
/// .fetch_one(&mut conn)
/// .await?;
///
/// // For Postgres this would have been inferred to be `Option<i32>`, MySQL `i32`
/// // and SQLite it wouldn't have worked at all because we couldn't know the type.
/// assert_eq!(record.id, MyInt4(1));
/// # }
/// ```
///
/// As mentioned, this allows specifying the type of a pure expression column which is normally
/// forbidden for SQLite as there's no way we can ask SQLite what type the column is expected to be.
///
/// ## Offline Mode (requires the `offline` feature)
/// The macros can be configured to not require a live database connection for compilation,
/// but it requires a couple extra steps:
///
@ -313,6 +382,36 @@ macro_rules! query_file_unchecked (
/// ## Nullability
/// Use `Option` for columns which may be `NULL` in order to avoid a runtime error being returned
/// from `.fetch_*()`.
///
/// ### Additional Column Type Override Option
/// In addition to the column type overrides supported by [query!], `query_as!()` supports an
/// additional override option:
///
/// If you select a column `foo as "foo: _"` (Postgres/SQLite) or `` foo as `foo: _` `` (MySQL)
/// it causes that column to be inferred based on the type of the corresponding field in the given
/// record struct. Runtime type-checking is still done so an error will be emitted if the types
/// are not compatible.
///
/// This allows you to override the inferred type of a column to instead use a custom-defined type:
///
/// ```rust,ignore
/// #[derive(sqlx::Type)]
/// #[sqlx(transparent)
/// struct MyInt4(i32);
///
/// struct Record {
/// id: MyInt4,
/// }
///
/// let my_int = MyInt4(1);
///
/// // Postgres/SQLite
/// sqlx::query!(r#"select 1 as "id: _""#) // MySQL: use "select 1 as `id: _`" instead
/// .fetch_one(&mut conn)
/// .await?;
///
/// assert_eq!(record.id, MyInt4(1));
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
macro_rules! query_as (