postgres_named_parameters/
lib.rs

1#![warn(missing_docs)]
2#![doc = include_str!("../README.md")]
3pub mod internal;
4
5pub use postgres;
6/// See the [Query] docs for details.
7pub use postgres_named_parameters_derive::Query;
8/// See the [Statement] docs for details.
9pub use postgres_named_parameters_derive::Statement;
10
11/// A `Statement` is a SQL statement that, unlike a [Query], does not return rows.
12/// Instead, it returns the number of rows that have been affected by the
13/// statement.
14///
15/// # Example
16/// `Statement` can be derived like so:
17/// ```no_run
18/// #[derive(Statement)]
19/// #[statement(sql = "DELETE FROM Person WHERE id = @id")]
20/// struct DeletePerson {
21///     // Define the statement's parameters
22///     id: i32
23/// }
24/// ```
25///
26/// It then can be used like so:
27/// ```no_run
28/// # #[derive(Statement)]
29/// # #[statement(sql = "DELETE FROM Person WHERE id = @id")]
30/// # struct DeletePerson {
31/// #     id: i32
32/// # }
33/// fn main() -> Result<(), postgres::Error> {
34///     let connection_string = std::env::var("POSTGRES_CONNECTION_STRING")
35///         .unwrap_or("host=localhost user=postgres".to_owned());
36///     let mut db = postgres::Client::connect(&connection_string, postgres::NoTls)?;
37///
38///     let delete_count = DeletePerson {
39///         id: 123
40///     }.execute_statement(&mut db)?;
41///
42///     println!("Deleted {} people", delete_count);
43///     Ok(())
44/// }
45/// ```
46/// For a more thorough example (including bulk queries), see the example
47/// project folder in the [GitHub repository](https://github.com/jmoore34/postgres-named-parameters).
48///
49/// # Notes
50/// * In order to use `#[derive(Statement)`, you must also provide the helper
51///   attribute `#[statement(sql = "...")`
52///     * The `sql` parameter is required and must be a string literal
53///     * Unlike [Query], there is no `row` parameter because
54///       `Statement` does not return rows (but rather a count of the number of
55///       rows affected)
56/// * At compile time, the derive macro will check that the parameter names you
57///   used in your query match the field names defined in the struct. A mismatch
58///   (e.g. using "@idd" instead of "@id" when the field name is `id`) will
59///   cause a compiler error.
60/// * If you want to include a single literal `@` in your SQL, you must escape
61///   it by doubling it (`@@`)
62pub trait Statement {
63    /// Execute a given statement on a given database connection or transaction,
64    /// and return the number of rows that were affected.
65    ///
66    /// For the sole argument you can pass either a database connection (i.e.
67    /// [postgres::Client]) or a transaction (i.e. [postgres::Transaction]).
68    fn execute_statement(
69        &self,
70        connection: &mut impl postgres::GenericClient,
71    ) -> Result<u64, postgres::error::Error>;
72}
73
74/// A `Query` is a SQL query that returns rows from the database.
75///
76/// # Example
77/// `Query` can be derived like so:
78/// ```no_run
79/// # #[derive(FromRow, Debug)]
80/// # struct Person {
81/// #     first_name: String,
82/// #     last_name: String,
83/// #     hobby: Option<String>,
84/// #     alive: bool,
85/// # }
86/// #[derive(Query)]
87/// #[query(
88///     // Write the query using named parameters
89///     sql = "
90///       SELECT *
91///       FROM Person
92///       WHERE (first_name = @name OR last_name = @name)
93///       AND alive = @alive",
94///     // Specify what type the rows should be decoded to
95///     row = Person
96/// )]
97/// struct GetPeople<'a> {
98///     // Define the query's parameters
99///     alive: bool,
100///     name: &'a str,
101/// }
102/// ```
103/// Note that the struct you specify for `row` must implement
104/// [FromRow](postgres_from_row::FromRow). You can do this by using
105/// `#[derive(FromRow)]`, which you can get by adding
106/// [postgres-from-row](https://crates.io/crates/postgres-from-row) to your
107/// `Cargo.toml`. (Note: as of time of writing, [postgres-from-row](https://crates.io/crates/postgres-from-row) does not yet
108/// support [borrowed fields](https://github.com/remkop22/postgres-from-row/issues/12).)
109/// ```no_run
110/// #[derive(FromRow, Debug)]
111/// struct Person {
112///     first_name: String,
113///     last_name: String,
114///     hobby: Option<String>,
115///     alive: bool,
116/// }
117/// ````
118///
119/// Your can then use your query like this:
120/// ```no_run
121/// # #[derive(FromRow, Debug)]
122/// # struct Person {
123/// #     first_name: String,
124/// #     last_name: String,
125/// #     hobby: Option<String>,
126/// #     alive: bool,
127/// # }
128/// # #[query(
129/// #     // Write the query using named parameters
130/// #     sql = "
131/// #       SELECT *
132/// #       FROM Person
133/// #       WHERE (first_name = @name OR last_name = @name)
134/// #       AND alive = @alive",
135/// #     // Specify what type the rows should be decoded to
136/// #     row = Person
137/// # )]
138/// # struct GetPeople<'a> {
139/// #     alive: bool,
140/// #     name: &'a str,
141/// # }
142/// fn main() -> Result<(), postgres::Error> {
143///     let connection_string = std::env::var("POSTGRES_CONNECTION_STRING")
144///         .unwrap_or("host=localhost user=postgres".to_owned());
145///     let mut db = postgres::Client::connect(&connection_string, postgres::NoTls)?;
146///
147///     let people = GetPeople {
148///         alive: true,
149///         name: "John",
150///     }
151///     .query_all(&mut db)?;
152///
153///     println!("Found: {:?}", people);
154///     Ok(())
155/// }
156/// ```
157/// At compile time, the SQL is transformed to use numbered parameters. For
158/// example, the above query will roughly desugar to:
159/// ```no_run
160/// # fn main() -> Result<(), postgres::Error> {
161/// #     let connection_string = std::env::var("POSTGRES_CONNECTION_STRING")
162/// #         .unwrap_or("host=localhost user=postgres".to_owned());
163/// #     let mut db = postgres::Client::connect(&connection_string, postgres::NoTls)?;
164/// let people: Vec<Person> = db.query(
165///     "SELECT *
166///      FROM Person
167///      WHERE (first_name = $2 OR last_name = $2)
168///      AND alive = $1",
169///     &[&true, &"John"],
170/// )?
171/// .iter()
172/// .map(Person::try_from_row)
173/// .collect::<Result<Vec<Person>,postgres::Error>>()?;
174/// #   Ok(())
175/// # }
176/// ````
177///
178/// For a more thorough example (including bulk queries), see the example
179/// project folder in the [GitHub repository](https://github.com/jmoore34/postgres-named-parameters).
180///
181/// # Notes
182/// * In order to use `#[derive(Query)`, you must also provide the helper
183///   attribute `#[statement(sql = "...", row = ...)`
184///     * Both the `sql` and `row` parameters are required
185///     * The `sql` parameter must be a string literal
186///     * The `row` parameter must implement
187///       [FromRow](postgres_from_row::FromRow) (see above).
188/// * At compile time, the derive macro will check that the parameter names you
189///   used in your query match the field names defined in the struct. A mismatch
190///   (e.g. using "@naame" instead of "@name" when the field name is `name`) will
191///   cause a compiler error.
192/// * If you want to include a single literal `@` in your SQL, you must escape
193///   it by doubling it (`@@`)
194pub trait Query {
195    /// The type that each individual row returned from the query should decode
196    /// to. You specify this type in the derive macro using the `row` parameter.
197    /// Note that this type must implement
198    /// [FromRow](postgres_from_row::FromRow) on the struct you intend to decode
199    /// each row to. You can do this by using
200    /// `#[derive(FromRow)`, which you can get by adding
201    /// [postgres-from-row](https://crates.io/crates/postgres-from-row) to your
202    /// `Cargo.toml`.
203    type Row: postgres_from_row::FromRow;
204
205    /// Run the query and return all the rows in a vector.
206    ///
207    /// For the sole argument you can pass either a database connection (i.e.
208    /// [postgres::Client]) or a transaction (i.e. [postgres::Transaction]).
209    fn query_all(
210        &self,
211        connection: &mut impl postgres::GenericClient,
212    ) -> Result<Vec<Self::Row>, postgres::error::Error>;
213
214    /// Run the query, expecting exactly one or zero rows. Return `Ok(None)` if
215    /// there are no rows, and return an `Err` if there is more than one row.
216    /// See also: [query_one](Query::query_one).
217    ///
218    /// For the sole argument you can pass either a database connection (i.e.
219    /// [postgres::Client]) or a transaction (i.e. [postgres::Transaction]).
220    fn query_opt(
221        &self,
222        connection: &mut impl postgres::GenericClient,
223    ) -> Result<Option<Self::Row>, postgres::error::Error>;
224
225    /// Run the query, expecting exactly one row. Return an `Err` if no rows or
226    /// more than one row are returned. See also: [query_opt](Query::query_opt).
227    ///
228    /// For the sole argument you can pass either a database connection (i.e.
229    /// [postgres::Client]) or a transaction (i.e. [postgres::Transaction]).
230    fn query_one(
231        &self,
232        connection: &mut impl postgres::GenericClient,
233    ) -> Result<Self::Row, postgres::error::Error>;
234}