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
//! 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, //! }; //! ``` //! //! [`Query`]: struct.Query.html //! [`query!`]: macro.Query.html //! [`FromSqlRow`]: extract/trait.FromSqlRow.html //! [`derive(FromSqlRow)`]: derive.FromSqlRow.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 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`, ... (preferred) /// 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)>, }