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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
//! Helper macros and traits built around //! [tokio-postgres](https://docs.rs/tokio-postgres/0.5.1/tokio_postgres/index.html) to define //! queries with human readable parameters and return values. //! //! # Example //! //! ``` //! # use tokio_postgres::Client; //! # use postgres_query::{query, FromSqlRow, Result}; //! # fn connect() -> Client { unimplemented!() } //! # async fn foo() -> Result<()> { //! // Connect to the database //! let client: Client = connect(/* ... */); //! //! // Construct the query //! let query = query!( //! "SELECT age, name FROM people WHERE age >= $min_age", //! min_age = 18 //! ); //! //! // Define the structure of the data returned from the query //! #[derive(FromSqlRow)] //! struct Person { //! age: i32, //! name: String, //! } //! //! // Execute the query //! let people: Vec<Person> = query.fetch(&client).await?; //! //! for person in people { //! println!("{} is {} years young", person.name, person.age); //! } //! # Ok(()) //! # } //! ``` //! //! # Queries //! //! The preferred way of constructing a new [`Query`] is through the [`query!`] macro. It uses a //! syntax similar to the `format!(...)` family of macros from the standard library. The first //! parameter is the SQL query and is always given as a string literal (this might be relaxed in the //! future). This string literal may contain parameter bindings on the form `$ident` where `ident` //! is any valid Rust identifier (`$abc`, `$value_123`, etc.). //! //! ``` //! # use postgres_query::query; //! let age = 42; //! let insert_person = query!( //! "INSERT INTO people VALUES ($age, $name)", //! name = "John Wick", // Binds "$name" to "John Wick" //! age, // Binds "$age" to the value of `age` //! ); //! ``` //! //! During compilation the query is converted into the format expected by PostgreSQL: parameter //! bindings are converted to using numbers ($1, $2, etc.) and the actual parameter values are put //! into a 1-indexed array. The code snippet above would be expanded into the following: //! //! ``` //! # use postgres_query::*; //! let age = 42; //! let insert_person = Query { //! sql: "INSERT INTO people VALUES ($1, $2)", //! parameters: vec![&age, &"John Wick"], //! }; //! ``` //! //! # Data Extraction //! //! In addition to helping you define new queries this crate provides the [`FromSqlRow`] trait which //! makes it easy to extract typed values from the resulting rows. The easiest way to implement this //! trait for new `struct`s is to use the included [`derive(FromSqlRow)`] macro. //! //! - If used on a tuple struct, values will be extracted from the corresponding columns based on //! their position in the tuple. //! - If used on a stuct with named fields, values will be extracted from the column with the same //! name as the field. //! //! ``` //! # use postgres_query::*; //! #[derive(FromSqlRow)] //! struct TupleData(i32, String); //! //! #[derive(FromSqlRow)] //! struct NamedData { //! age: i32, //! name: String, //! }; //! ``` //! //! # Caching queries //! //! From time to time you probably want to execute the same query multiple times, but with different //! parameters. In times like these we can decrease the load on the database by preparing our //! queries before executing them. By wrapping a client in a [`Caching`] struct this behaviour is //! automatically provided for all queries that originate from this crate: //! //! ```rust //! # use tokio_postgres::Client; //! # use postgres_query::{query, Result, Caching}; //! # fn connect() -> Client { unimplemented!() } //! # async fn foo() -> Result<()> { //! // Connect to the database //! let client: Client = connect(/* ... */); //! //! // Wrap the client in a query cache //! let cached_client = Caching::new(client); //! //! for age in 0..100i32 { //! let query = query!("SELECT name, weight FROM people WHERE age = $age", age); //! //! // The query is prepared and cached the first time it's executed. //! // All subsequent fetches will use the cached Statement. //! let people: Vec<(String, i32)> = query.fetch(&cached_client).await?; //! //! /* Do something with people */ //! } //! # Ok(()) //! # } //! ``` //! //! [`Query`]: struct.Query.html //! [`query!`]: macro.Query.html //! [`FromSqlRow`]: extract/trait.FromSqlRow.html //! [`derive(FromSqlRow)`]: derive.FromSqlRow.html //! [`Caching`]: client/struct.Caching.html pub mod client; pub mod execute; pub mod extract; mod error; use postgres_types::ToSql; use proc_macro_hack::proc_macro_hack; pub use client::Caching; pub use error::{Error, Result}; pub use extract::FromSqlRow; /// Extract values from a row. /// /// - If used on a tuple struct, values will be extracted from the corresponding columns based on /// their position in the tuple. /// - If used on a stuct with named fields, values will be extracted from the column with the same /// name as the field. /// /// # Example /// /// ``` /// # use postgres_query::*; /// #[derive(FromSqlRow)] /// struct TupleData(i32, String); /// /// #[derive(FromSqlRow)] /// struct NamedData { /// age: i32, /// name: String, /// }; /// ``` pub use postgres_query_macro::FromSqlRow; /// Constructs a new query. /// /// # Usage /// /// The first parameter is the SQL query and is always given as a string literal (this might be /// relaxed in the future). This string literal may contain parameter bindings on the form `$ident` /// where `ident` is any valid Rust identifier (`$abc`, `$value_123`, etc.). The order of the /// parameters does not matter. /// /// ``` /// # use postgres_query::query; /// let age = 42; /// let insert_person = query!( /// "INSERT INTO people VALUES ($age, $name)", /// name = "John Wick", // Binds "$name" to "John Wick" /// age, // Binds "$age" to the value of `age` /// ); /// ``` /// /// During compilation the query is converted into the format expected by PostgreSQL: parameter /// bindings are converted to using numbers (`$1`, `$2`, etc.) and the actual parameter values are /// put into a 1-indexed array. The code snippet above would be expanded into the following: /// /// ``` /// # use postgres_query::*; /// let age = 42; /// let insert_person = Query { /// sql: "INSERT INTO people VALUES ($1, $2)", /// parameters: vec![&age, &"John Wick"], /// }; /// ``` #[proc_macro_hack] pub use postgres_query_macro::query; /// A static query with dynamic parameters. /// /// # Usage /// /// The preferred way of constructing a [`Query`] is by using the [`query!`] macro. /// /// When executing the query you have two options, either: /// /// 1. use the provided methods: `execute`, `fetch`, `query`, etc. /// 2. use the `sql` and `parameters` fields as arguments to the standard [`Client`] methods /// /// ``` /// # use tokio_postgres::{Client, Row}; /// # use postgres_query::{query, FromSqlRow, Result}; /// # fn connect() -> Client { unimplemented!() } /// # async fn foo() -> Result<(), Box<dyn std::error::Error>> { /// #[derive(FromSqlRow)] /// struct Person { /// age: i32, /// name: String, /// } /// /// let client: Client = connect(/* ... */); /// let query = query!("SELECT age, name FROM people"); /// /// // Option 1 /// let people: Vec<Person> = query.fetch(&client).await?; /// /// // Option 2 /// let rows: Vec<Row> = client.query(query.sql, &query.parameters).await?; /// let people: Vec<Person> = Person::from_row_multi(&rows)?; /// # Ok(()) /// # } /// ``` /// /// [`Query`]: struct.Query.html /// [`query!`]: macro.query.html /// [`Client`]: https://docs.rs/tokio-postgres/0.5.1/tokio_postgres/struct.Client.html #[derive(Debug, Clone)] pub struct Query<'a> { pub sql: &'static str, pub parameters: Vec<&'a (dyn ToSql + Sync)>, }