Update documentation

This commit is contained in:
Thom Chiovoloni 2020-11-03 00:46:54 -08:00
parent 032aea73b8
commit 2461ebf62f
3 changed files with 182 additions and 28 deletions

View File

@ -187,7 +187,7 @@ macro_rules! params {
/// } /// }
/// ///
/// fn add_person(conn: &Connection, person: &Person) -> Result<()> { /// fn add_person(conn: &Connection, person: &Person) -> Result<()> {
/// conn.execute_named( /// conn.execute(
/// "INSERT INTO person (name, age_in_years, data) /// "INSERT INTO person (name, age_in_years, data)
/// VALUES (:name, :age, :data)", /// VALUES (:name, :age, :data)",
/// named_params!{ /// named_params!{
@ -511,7 +511,7 @@ impl Connection {
/// ```rust,no_run /// ```rust,no_run
/// # use rusqlite::{Connection, Result}; /// # use rusqlite::{Connection, Result};
/// fn insert(conn: &Connection) -> Result<usize> { /// fn insert(conn: &Connection) -> Result<usize> {
/// conn.execute_named( /// conn.execute(
/// "INSERT INTO test (name) VALUES (:name)", /// "INSERT INTO test (name) VALUES (:name)",
/// rusqlite::named_params!{ ":name": "one" }, /// rusqlite::named_params!{ ":name": "one" },
/// ) /// )

View File

@ -5,16 +5,162 @@ mod sealed {
/// that are allowed are ones in this crate. /// that are allowed are ones in this crate.
pub trait Sealed {} pub trait Sealed {}
} }
// must not be `pub use`.
use sealed::Sealed; use sealed::Sealed;
/// Trait used for parameter sets passed into SQL statements/queries. /// Trait used for [sets of parameter][params] passed into SQL
/// statements/queries.
/// ///
/// Currently, this trait can only be implemented inside this crate. /// [params]: https://www.sqlite.org/c3ref/bind_blob.html
///
/// Note: Currently, this trait can only be implemented inside this crate.
/// Additionally, it's methods (which are `doc(hidden)`) should currently not be
/// considered part of the stable API, although it's possible they will
/// stabilize in the future.
///
/// # Passing parameters to SQLite
///
/// Many functions in this library let you pass parameters to SQLite. Doing this
/// lets you avoid any risk of SQL injection, and is simpler than escaping
/// things manually. Aside from deprecated functions and a few helpers, this is
/// indicated by the function taking a generic argument that implements `Params`
/// (this trait).
///
/// ## Positional parameters
///
/// For cases where you want to pass a list of parameters where the number of
/// parameters is known at compile time, this can be done in one of the
/// following ways:
///
/// - Using the [`rusqlite::params!`](crate::params!) macro, e.g.
/// `thing.query(rusqlite::params![1, "foo", bar])`. This is mostly useful for
/// heterogeneous lists of parameters, or lists where the number of parameters
/// exceeds 32.
///
/// - For small heterogeneous lists of parameters, they can either be passed as:
///
/// - an array, as in `thing.query([1i32, 2, 3, 4])` or `thing.query(["foo",
/// "bar", "baz"])`.
///
/// - a reference to an array of references, as in `thing.query(&["foo",
/// "bar", "baz"])` or `thing.query(&[&1i32, &2, &3])`.
///
/// (Note: in this case we don't implement this for slices for coherence
/// reasons, so it really is only for the "reference to array" types —
/// hence why the number of parameters must be <= 32 or you need to
/// reach for `rusqlite::params!`)
///
/// Unfortunately, in the current design it's not possible to allow this for
/// references to arrays of non-references (e.g. `&[1i32, 2, 3]`). Code like
/// this should instead either use `params!`, an array literal, a `&[&dyn
/// ToSql]` or if none of those work, [`ParamsFromIter`].
///
/// - As a slice of `ToSql` trait object references, e.g. `&[&dyn ToSql]`. This
/// is mostly useful for passing parameter lists around as arguments without
/// having every function take a generic `P: Params`.
///
/// ### Example (positional)
///
/// ```rust,no_run
/// # use rusqlite::{Connection, Result, params};
/// fn update_rows(conn: &Connection) -> Result<()> {
/// let mut stmt = conn.prepare("INSERT INTO test (a, b) VALUES (?, ?)")?;
///
/// // Using `rusqlite::params!`:
/// stmt.execute(params![1i32, "blah"])?;
///
/// // array literal — non-references
/// stmt.execute([2i32, 3i32])?;
///
/// // array literal — references
/// stmt.execute(["foo", "bar"])?;
///
/// // Slice literal, references:
/// stmt.execute(&[&2i32, &3i32])?;
///
/// // Note: The types behind the references don't have to be `Sized`
/// stmt.execute(&["foo", "bar"])?;
///
/// // However, this doesn't work (see above):
/// // stmt.execute(&[1i32, 2i32])?;
/// Ok(())
/// }
/// ```
///
/// ## Named parameters
///
/// SQLite lets you name parameters using a number of conventions (":foo",
/// "@foo", "$foo"). You can pass named parameters in to SQLite using rusqlite
/// in a few ways:
///
/// - Using the [`rusqlite::named_params!`](crate::named_params!) macro, as in
/// `stmt.execute(named_params!{ ":name": "foo", ":age": 99 })`. Similar to
/// the `params` macro, this is most useful for heterogeneous lists of
/// parameters, or lists where the number of parameters exceeds 32.
///
/// - As a slice of `&[(&str, &dyn ToSql)]`. This is what essentially all of
/// these boil down to in the end, conceptually at least. In theory you can
/// pass this as `stmt.
///
/// - As array references, similar to the positional params. This looks like
/// `thing.query(&[(":foo", &1i32), (":bar", &2i32)])` or
/// `thing.query(&[(":foo", "abc"), (":bar", "def")])`.
///
/// Note: Unbound named parameters will be left to the value they previously
/// were bound with, falling back to `NULL` for parameters which have never been
/// bound.
///
/// ### Example (named)
///
/// ```rust,no_run
/// # use rusqlite::{Connection, Result, named_params};
/// fn insert(conn: &Connection) -> Result<()> {
/// let mut stmt = conn.prepare("INSERT INTO test (key, value) VALUES (:key, :value)")?;
/// // Using `rusqlite::params!`:
/// stmt.execute(named_params!{ ":key": "one", ":val": 2 })?;
/// // Alternatively:
/// stmt.execute(&[(":key", "three"), (":val", "four")])?;
/// // Or:
/// stmt.execute(&[(":key", &100), (":val", &200)])?;
/// Ok(())
/// }
/// ```
///
/// ## No parameters
///
/// You can just use an empty array literal for no params. The
/// `rusqlite::NO_PARAMS` constant which was so common in previous versions of
/// this library is no longer needed.
///
/// ### Example (no parameters)
///
/// ```rust,no_run
/// # use rusqlite::{Connection, Result, params};
/// fn delete_all_users(conn: &Connection) -> Result<()> {
/// // Just use an empty array (e.g. `[]`) for no params.
/// conn.execute("DELETE FROM users", [])?;
/// Ok(())
/// }
/// ```
///
/// ## Dynamic parameter list
///
/// If you have a number of parameters which is unknown at compile time (for
/// example, building a dynamic query at runtime), you have two choices:
///
/// - Use a `&[&dyn ToSql]`, which is nice if you have one otherwise might be
/// annoying.
/// - Use the [`ParamsFromIter`] type. This essentially lets you wrap an
/// iterator some `T: ToSql` with something that implements `Params`.
///
/// A lot of the considerations here are similar either way, so you should see
/// the [`ParamsFromIter`] documentation for more info / examples.
pub trait Params: Sealed { pub trait Params: Sealed {
/// Binds the parameters to the statement. It is unlikely calling this // XXX not public api, might not need to expose.
/// explicitly will do what you want. Please use `Statement::query` or //
/// similar directly. // Binds the parameters to the statement. It is unlikely calling this
// explicitly will do what you want. Please use `Statement::query` or
// similar directly.
//
// For now, just hide the function in the docs... // For now, just hide the function in the docs...
#[doc(hidden)] #[doc(hidden)]
fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()>; fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()>;
@ -69,6 +215,10 @@ macro_rules! impl_for_array_ref {
} }
)+}; )+};
} }
// Following libstd/libcore's (old) lead, implement this for arrays up to `[_;
// 32]`. Note `[_; 0]` is intentionally omitted for coherence reasons, see the
// note above the impl of `[&dyn ToSql; 0]` for more information.
impl_for_array_ref!( impl_for_array_ref!(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
18 19 20 21 22 23 24 25 26 27 29 30 31 32 18 19 20 21 22 23 24 25 26 27 29 30 31 32
@ -154,17 +304,21 @@ impl_for_array_ref!(
/// production-ready: /// production-ready:
/// ///
/// - production code should ensure `usernames` isn't so large that it will /// - production code should ensure `usernames` isn't so large that it will
/// surpass [`conn.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER)`][limits]) /// surpass [`conn.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER)`][limits]),
/// (chunking if too large). /// chunking if too large. (Note that the limits api requires rusqlite to have
/// the "limits" feature).
/// ///
/// - `repeat_vars` can be implemented in a way that avoids needing to allocate /// - `repeat_vars` can be implemented in a way that avoids needing to allocate
/// a String. /// a String.
/// ///
/// - Etc...
///
/// [limits]: crate::Connection::limit /// [limits]: crate::Connection::limit
/// ///
/// This complexity reflects the fact that `ParamsFromIter` is mainly intended /// This complexity reflects the fact that `ParamsFromIter` is mainly intended
/// for advanced use cases — most of the time you should know how many /// for advanced use cases — most of the time you should know how many
/// parameters you have statically. /// parameters you have statically (and if you don't, you're either doing
/// something tricky, or should take a moment to think about the design).
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ParamsFromIter<I>(I); pub struct ParamsFromIter<I>(I);

View File

@ -34,11 +34,14 @@ impl Statement<'_> {
/// # use rusqlite::{Connection, Result, params}; /// # use rusqlite::{Connection, Result, params};
/// fn update_rows(conn: &Connection) -> Result<()> { /// fn update_rows(conn: &Connection) -> Result<()> {
/// let mut stmt = conn.prepare("UPDATE foo SET bar = 'baz' WHERE qux = ?")?; /// let mut stmt = conn.prepare("UPDATE foo SET bar = 'baz' WHERE qux = ?")?;
/// /// // The `rusqlite::params!` macro is mostly useful when the parameters do not
/// // all have the same type, or if there are more than 32 parameters
/// // at once.
/// stmt.execute(params![1i32])?; /// stmt.execute(params![1i32])?;
/// // Similarly... /// // However, it's not required, many cases are fine as:
/// stmt.execute(&[&2i32])?; /// stmt.execute(&[&2i32])?;
/// /// // Or even:
/// stmt.execute([2i32])?;
/// Ok(()) /// Ok(())
/// } /// }
/// ``` /// ```
@ -46,21 +49,18 @@ impl Statement<'_> {
/// ### Use with named parameters /// ### Use with named parameters
/// ///
/// ```rust,no_run /// ```rust,no_run
/// # use rusqlite::{Connection, Result};
/// fn insert(conn: &Connection) -> Result<usize> {
/// let mut stmt = conn.prepare("INSERT INTO test (name) VALUES (:name)")?;
/// stmt.execute(&[(":name", &"one")])
/// }
/// ```
///
/// Note, the `named_params` macro is provided for syntactic convenience,
/// and so the above example could also be written as:
///
/// ```rust,no_run
/// # use rusqlite::{Connection, Result, named_params}; /// # use rusqlite::{Connection, Result, named_params};
/// fn insert(conn: &Connection) -> Result<usize> { /// fn insert(conn: &Connection) -> Result<()> {
/// let mut stmt = conn.prepare("INSERT INTO test (name) VALUES (:name)")?; /// let mut stmt = conn.prepare("INSERT INTO test (key, value) VALUES (:key, :value)")?;
/// stmt.execute(named_params!{":name": "one"}) /// // The `rusqlite::named_params!` macro (like `params!`) is useful for heterogeneous
/// // sets of parameters (where all parameters are not the same type), or for queries
/// // with many (more than 32) statically known parameters.
/// stmt.execute(named_params!{ ":key": "one", ":val": 2 })?;
/// // However, named parameters can also be passed like:
/// stmt.execute(&[(":key", "three"), (":val", "four")])?;
/// // Or even: (note that a &T is required for the value type, currently)
/// stmt.execute(&[(":key", &100), (":val", &200)])?;
/// Ok(())
/// } /// }
/// ``` /// ```
/// ///