doc: adjust macros documentation

Signed-off-by: Austin Bonander <austin@launchbadge.com>
This commit is contained in:
Austin Bonander 2020-07-21 22:30:45 -07:00
parent 94aa698581
commit 67ad43491d
No known key found for this signature in database
GPG key ID: 4E7DA63E66AFC37E

View file

@ -1,7 +1,7 @@
/// Statically checked SQL query with `println!()` style syntax.
///
/// 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:
/// This expands to an instance of [query::Map][crate::query::Map] that outputs an ad-hoc anonymous
/// struct type, if the query has output columns, or `()` (unit) otherwise:
///
/// ```rust,ignore
/// # use sqlx::Connect;
@ -36,8 +36,9 @@
/// * Or, `sqlx-data.json` must exist at the workspace root. See [Offline Mode](#offline-mode)
/// below.
///
/// * The query must be a string literal or else it cannot be introspected (and thus cannot
/// be dynamic or the result of another macro).
/// * The query must be a string literal, or concatenation of string literals using `+` (useful
/// for queries generated by macro), or else it cannot be introspected (and thus cannot be dynamic
/// or the result of another macro).
///
/// * The `QueryAs` instance will be bound to the same database type as `query!()` was compiled
/// against (e.g. you cannot build against a Postgres database and then run the query against
@ -81,7 +82,7 @@
/// Bind parameters in the SQL string are specific to the database backend:
///
/// * Postgres: `$N` where `N` is the 1-based positional argument index
/// * MySQL: `?` which matches arguments in order that it appears in the query
/// * MySQL/SQLite: `?` which matches arguments in order that it appears in the query
///
/// ## Nullability: Bind Parameters
/// For a given expected type `T`, both `T` and `Option<T>` are allowed (as well as either
@ -90,8 +91,11 @@
///
/// Note, however, if binding in a `where` clause, that equality comparisons with `NULL` may not
/// work as expected; instead you must use `IS NOT NULL` or `IS NULL` to check if a column is not
/// null or is null, respectively. Note that `IS [NOT] NULL` cannot be bound as a parameter either;
/// you must modify your query string instead.
/// null or is null, respectively.
///
/// In Postgres and MySQL you may also use `IS [NOT] DISTINCT FROM` to compare with a possibly
/// `NULL` value. In MySQL `IS NOT DISTINCT FROM` can be shortened to `<=>`.
/// In SQLite you can us `IS` or `IS NOT`. Note that operator precedence may be different.
///
/// ## Nullability: Output Columns
/// In most cases, the database engine can tell us whether or not a column may be `NULL`, and
@ -111,7 +115,7 @@
/// `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!], or see below.
/// To override the nullability of an output column, [see below](#type-overrides-output-columns).
///
/// ## Type Overrides: Bind Parameters (Postgres only)
/// For typechecking of bind parameters, casts using `as` are treated as overrides for the inferred
@ -136,7 +140,8 @@
/// 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!` `` (MySQL) overrides
/// ##### Force Not-Null
/// Selecting a column `foo as "foo!"` (Postgres / SQLite) or `` foo as `foo!` `` (MySQL) 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:
///
@ -154,7 +159,9 @@
/// # }
///
/// ```
/// * selecting a column `foo as "foo?"` (Postgres / SQLite) or `` foo as `foo?` `` (MySQL) overrides
///
/// ##### Force Nullable
/// Selecting a column `foo as "foo?"` (Postgres / SQLite) or `` foo as `foo?` `` (MySQL) overrides
/// inferred nullability and forces the column to be treated as nullable; this is provided mainly
/// for symmetry with `!`, but also because nullability inference currently has some holes and false
/// negatives that may not be completely fixable without doing our own complex analysis on the given
@ -200,7 +207,8 @@
///
/// See [launchbadge/sqlx#367](https://github.com/launchbadge/sqlx/issues/367) for more details on this issue.
///
/// * selecting a column `foo as "foo: T"` (Postgres / SQLite) or `` foo as `foo: T` `` (MySQL)
/// ##### Force a Different/Custom Type
/// 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):
@ -355,7 +363,7 @@ macro_rules! query_file_unchecked (
///
/// This lets you return the struct from a function or add your own trait implementations.
///
/// No trait implementations are required; the macro maps rows using a struct literal
/// **No trait implementations are required**; the macro maps rows using a struct literal
/// where the names of columns in the query are expected to be the same as the fields of the struct
/// (but the order does not need to be the same). The types of the columns are based on the
/// query and not the corresponding fields of the struct, so this is type-safe as well.
@ -363,9 +371,17 @@ macro_rules! query_file_unchecked (
/// This enforces a few things:
/// * The query must output at least one column.
/// * The column names of the query must match the field names of the struct.
/// * The field types must be the Rust equivalent of their SQL counterparts; see the corresponding
/// module for your database for mappings:
/// * Postgres: [crate::postgres::types]
/// * MySQL: [crate::mysql::types]
/// * SQLite: [crate::sqlite::types]
/// * MSSQL: [crate::mssql::types]
/// * If a column may be `NULL`, the corresponding field's type must be wrapped in `Option<_>`.
/// * Neither the query nor the struct may have unused fields.
///
/// The only modification to the syntax is that the struct name is given before the SQL string:
/// The only modification to the `query!()` syntax is that the struct name is given before the SQL
/// string:
/// ```rust,ignore
/// # use sqlx::Connect;
/// # #[cfg(all(feature = "mysql", feature = "runtime-async-std"))]
@ -400,11 +416,7 @@ macro_rules! query_file_unchecked (
/// # fn main() {}
/// ```
///
/// ## 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
/// ### Column Type Override: Infer from Struct Field
/// In addition to the column type overrides supported by [query!], `query_as!()` supports an
/// additional override option:
///
@ -427,12 +439,63 @@ macro_rules! query_file_unchecked (
/// let my_int = MyInt4(1);
///
/// // Postgres/SQLite
/// sqlx::query!(r#"select 1 as "id: _""#) // MySQL: use "select 1 as `id: _`" instead
/// sqlx::query_as!(Record, r#"select 1 as "id: _""#) // MySQL: use "select 1 as `id: _`" instead
/// .fetch_one(&mut conn)
/// .await?;
///
/// assert_eq!(record.id, MyInt4(1));
/// ```
///
/// ### Troubleshooting: "error: mismatched types"
/// If you get a "mismatched types" error from an invocation of this macro and the error
/// isn't pointing specifically at a parameter.
///
/// For example, code like this (using a Postgres database):
///
/// ```rust,ignore
/// struct Account {
/// id: i32,
/// name: Option<String>,
/// }
///
/// let account = sqlx::query_as!(
/// Account,
/// r#"SELECT id, name from (VALUES (1, 'Herp Derpinson')) accounts(id, name)"#,
/// )
/// .fetch_one(&mut conn)
/// .await?;
/// ```
///
/// Might produce an error like this:
/// ```text,ignore
/// error[E0308]: mismatched types
/// --> tests/postgres/macros.rs:126:19
/// |
/// 126 | let account = sqlx::query_as!(
/// | ___________________^
/// 127 | | Account,
/// 128 | | r#"SELECT id, name from (VALUES (1, 'Herp Derpinson')) accounts(id, name)"#,
/// 129 | | )
/// | |_____^ expected `i32`, found enum `std::option::Option`
/// |
/// = note: expected type `i32`
/// found enum `std::option::Option<i32>`
/// ```
///
/// This means that you need to check that any field of the "expected" type (here, `i32`) matches
/// the Rust type mapping for its corresponding SQL column (see the `types` module of your database,
/// listed above, for mappings). The "found" type is the SQL->Rust mapping that the macro chose.
///
/// In the above example, the returned column is inferred to be nullable because it's being
/// returned from a `VALUES` statement in Postgres, so the macro inferred the field to be nullable
/// and so used `Option<i32>` instead of `i32`. **In this specific case** we could use
/// `select id as "id!"` to override the inferred nullability because we know in practice
/// that column will never be `NULL` and it will fix the error.
///
/// Nullability inference and type overrides are discussed in detail in the docs for [query!].
///
/// It unfortunately doesn't appear to be possible right now to make the error specifically mention
/// the field; this probably requires the `const-panic` feature (still unstable as of Rust 1.45).
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
macro_rules! query_as (