Add params/named_params macro, and expose ToSql from top level

This commit is contained in:
Thom Chiovoloni 2019-01-29 15:33:57 -08:00
parent 18b8c390ab
commit d7c8d43fb4
2 changed files with 106 additions and 7 deletions

View File

@ -6,7 +6,7 @@
//! extern crate time; //! extern crate time;
//! //!
//! use rusqlite::types::ToSql; //! use rusqlite::types::ToSql;
//! use rusqlite::{Connection, NO_PARAMS}; //! use rusqlite::{Connection, params};
//! use time::Timespec; //! use time::Timespec;
//! //!
//! #[derive(Debug)] //! #[derive(Debug)]
@ -27,7 +27,7 @@
//! time_created TEXT NOT NULL, //! time_created TEXT NOT NULL,
//! data BLOB //! data BLOB
//! )", //! )",
//! NO_PARAMS, //! params![],
//! ) //! )
//! .unwrap(); //! .unwrap();
//! let me = Person { //! let me = Person {
@ -39,7 +39,7 @@
//! conn.execute( //! conn.execute(
//! "INSERT INTO person (name, time_created, data) //! "INSERT INTO person (name, time_created, data)
//! VALUES (?1, ?2, ?3)", //! VALUES (?1, ?2, ?3)",
//! &[&me.name as &ToSql, &me.time_created, &me.data], //! params![me.name, me.time_created, me.data],
//! ) //! )
//! .unwrap(); //! .unwrap();
//! //!
@ -47,7 +47,7 @@
//! .prepare("SELECT id, name, time_created, data FROM person") //! .prepare("SELECT id, name, time_created, data FROM person")
//! .unwrap(); //! .unwrap();
//! let person_iter = stmt //! let person_iter = stmt
//! .query_map(NO_PARAMS, |row| Person { //! .query_map(params![], |row| Person {
//! id: row.get(0), //! id: row.get(0),
//! name: row.get(1), //! name: row.get(1),
//! time_created: row.get(2), //! time_created: row.get(2),
@ -88,7 +88,9 @@ use std::sync::{Arc, Mutex, Once, ONCE_INIT};
use crate::cache::StatementCache; use crate::cache::StatementCache;
use crate::error::{error_from_handle, error_from_sqlite_code}; use crate::error::{error_from_handle, error_from_sqlite_code};
use crate::raw_statement::RawStatement; use crate::raw_statement::RawStatement;
use crate::types::{ToSql, ValueRef}; use crate::types::ValueRef;
pub use crate::types::ToSql;
pub use crate::statement::{Statement, StatementStatus}; pub use crate::statement::{Statement, StatementStatus};
@ -144,6 +146,77 @@ const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
/// To be used when your statement has no [parameter](https://sqlite.org/lang_expr.html#varparam). /// To be used when your statement has no [parameter](https://sqlite.org/lang_expr.html#varparam).
pub const NO_PARAMS: &[&dyn ToSql] = &[]; pub const NO_PARAMS: &[&dyn ToSql] = &[];
/// A macro making it more convenient to pass heterogeneous lists
/// of parameters as a `&[&dyn ToSql]`.
///
/// # Example
///
/// ```rust,no_run
/// # use rusqlite::{Result, Connection, params};
///
/// struct Person {
/// name: String,
/// age_in_years: u8,
/// data: Option<Vec<u8>>,
/// }
///
/// fn add_person(conn: &Connection, person: &Person) -> Result<()> {
/// conn.execute("INSERT INTO person (name, age_in_years, data)
/// VALUES (?1, ?2, ?3)",
/// params![person.name, person.age_in_years, person.data])?;
/// Ok(())
/// }
/// ```
#[macro_export]
macro_rules! params {
() => {
$crate::NO_PARAMS
};
($($param:expr),+ $(,)?) => {
&[$(&$param as &dyn $crate::ToSql),+]
};
}
/// A macro making it more convenient to pass lists of named parameters
/// as a `&[(&str, &dyn ToSql)]`.
///
/// # Example
///
/// ```rust,no_run
/// # use rusqlite::{Result, Connection, named_params};
///
/// struct Person {
/// name: String,
/// age_in_years: u8,
/// data: Option<Vec<u8>>,
/// }
///
/// fn add_person(conn: &Connection, person: &Person) -> Result<()> {
/// conn.execute_named(
/// "INSERT INTO person (name, age_in_years, data)
/// VALUES (:name, :age, :data)",
/// named_params!{
/// ":name": person.name,
/// ":age": person.age_in_years,
/// ":data": person.data,
/// }
/// )?;
/// Ok(())
/// }
/// ```
#[macro_export]
macro_rules! named_params {
() => {
&[]
};
// Note: It's a lot more work to support this as part of the same macro as
// `params!`, unfortunately.
($($param_name:literal: $param_val:expr),+ $(,)?) => {
&[$(($param_name, &$param_val as &dyn $crate::ToSql)),+]
};
}
/// A typedef of the result returned by many methods. /// A typedef of the result returned by many methods.
pub type Result<T> = result::Result<T, Error>; pub type Result<T> = result::Result<T, Error>;
@ -1644,7 +1717,7 @@ mod test {
let i_to_insert = i as i64; let i_to_insert = i as i64;
assert_eq!( assert_eq!(
insert_stmt insert_stmt
.execute(&[&i_to_insert as &dyn ToSql, &v]) .execute(params![i_to_insert, v])
.unwrap(), .unwrap(),
1 1
); );
@ -1902,7 +1975,7 @@ mod test {
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql).unwrap();
db.query_row("SELECT * FROM foo", NO_PARAMS, |r| { db.query_row("SELECT * FROM foo", params![], |r| {
assert_eq!(2, r.column_count()) assert_eq!(2, r.column_count())
}) })
.unwrap(); .unwrap();

View File

@ -112,6 +112,17 @@ impl<'conn> Statement<'conn> {
/// } /// }
/// ``` /// ```
/// ///
/// 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};
/// fn insert(conn: &Connection) -> Result<usize> {
/// let mut stmt = conn.prepare("INSERT INTO test (name) VALUES (:name)")?;
/// stmt.execute_named(named_params!{":name": "one"})
/// }
/// ```
///
/// # Failure /// # Failure
/// ///
/// Will return `Err` if binding parameters fails, the executed statement /// Will return `Err` if binding parameters fails, the executed statement
@ -205,6 +216,21 @@ impl<'conn> Statement<'conn> {
/// } /// }
/// ``` /// ```
/// ///
/// 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};
/// fn query(conn: &Connection) -> Result<()> {
/// let mut stmt = conn.prepare("SELECT * FROM test where name = :name")?;
/// let mut rows = stmt.query_named(named_params!{ ":name": "one" })?;
/// while let Some(row) = rows.next() {
/// // ...
/// }
/// Ok(())
/// }
/// ```
///
/// # Failure /// # Failure
/// ///
/// Will return `Err` if binding parameters fails. /// Will return `Err` if binding parameters fails.