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}