diff --git a/postgres/src/client.rs b/postgres/src/client.rs index 681b754e..95152c89 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -11,9 +11,15 @@ use tokio_postgres::{Error, Row, SimpleQueryMessage}; use crate::Config; use crate::{CopyOutReader, QueryIter, SimpleQueryIter, Statement, ToStatement, Transaction}; +/// A synchronous PostgreSQL client. +/// +/// This is a lightweight wrapper over the asynchronous tokio_postgres `Client`. pub struct Client(tokio_postgres::Client); impl Client { + /// A convenience function which parses a configuration string into a `Config` and then connects to the database. + /// + /// Requires the `runtime` Cargo feature (enabled by default). #[cfg(feature = "runtime")] pub fn connect(params: &str, tls_mode: T) -> Result where @@ -25,19 +31,64 @@ impl Client { params.parse::()?.connect(tls_mode) } + /// Returns a new `Config` object which can be used to configure and connect to a database. + /// + /// Requires the `runtime` Cargo feature (enabled by default). #[cfg(feature = "runtime")] pub fn configure() -> Config { Config::new() } + /// Creates a new prepared statement. + /// + /// Prepared statements can be executed repeatedly, and may contain query parameters (indicated by `$1`, `$2`, etc), + /// which are set when executed. Prepared statements can only be used with the connection that created them. pub fn prepare(&mut self, query: &str) -> Result { self.0.prepare(query).wait() } + /// Like `prepare`, but allows the types of query parameters to be explicitly specified. + /// + /// The list of types may be smaller than the number of parameters - the types of the remaining parameters will be + /// inferred. For example, `client.prepare_typed(query, &[])` is equivalent to `client.prepare(query)`. pub fn prepare_typed(&mut self, query: &str, types: &[Type]) -> Result { self.0.prepare_typed(query, types).wait() } + /// Executes a statement, returning the number of rows modified. + /// + /// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list + /// provided, 1-indexed. + /// + /// If the statement does not modify any rows (e.g. `SELECT`), 0 is returned. + /// + /// The `query` argument can either be a `Statement`, or a raw query string. If the same statement will be + /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front + /// with the `prepare` method. + /// + /// # Panics + /// + /// Panics if the number of parameters provided does not match the number expected. + /// + /// # Example + /// + /// ```no_run + /// use postgres::{Client, NoTls}; + /// + /// # fn main() -> Result<(), postgres::Error> { + /// let mut client = Client::connect("host=localhost user=postgres", NoTls)?; + /// + /// let bar = 1i32; + /// let baz = true; + /// let rows_updated = client.execute( + /// "UPDATE foo SET bar = $1 WHERE baz = $2", + /// &[&bar, &baz], + /// )?; + /// + /// println!("{} rows updated", rows_updated); + /// # Ok(()) + /// # } + /// ``` pub fn execute(&mut self, query: &T, params: &[&dyn ToSql]) -> Result where T: ?Sized + ToStatement, @@ -46,6 +97,37 @@ impl Client { self.0.execute(&statement, params).wait() } + /// Executes a statement, returning the resulting rows. + /// + /// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list + /// provided, 1-indexed. + /// + /// The `query` argument can either be a `Statement`, or a raw query string. If the same statement will be + /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front + /// with the `prepare` method. + /// + /// The `query_iter` method can be used to avoid buffering all rows in memory at once. + /// + /// # Panics + /// + /// Panics if the number of parameters provided does not match the number expected. + /// + /// # Examples + /// + /// ```no_run + /// use postgres::{Client, NoTls}; + /// + /// # fn main() -> Result<(), postgres::Error> { + /// let mut client = Client::connect("host=localhost user=postgres", NoTls)?; + /// + /// let baz = true; + /// for row in client.query("SELECT foo FROM bar WHERE baz = $1", &[&baz])? { + /// let foo: i32 = row.get("foo"); + /// println!("foo: {}", foo); + /// } + /// # Ok(()) + /// # } + /// ``` pub fn query(&mut self, query: &T, params: &[&dyn ToSql]) -> Result, Error> where T: ?Sized + ToStatement, @@ -53,6 +135,31 @@ impl Client { self.query_iter(query, params)?.collect() } + /// Like `query`, except that it returns a fallible iterator over the resulting rows rather than buffering the + /// response in memory. + /// + /// # Panics + /// + /// Panics if the number of parameters provided does not match the number expected. + /// + /// # Examples + /// + /// ```no_run + /// use postgres::{Client, NoTls}; + /// use fallible_iterator::FallibleIterator; + /// + /// # fn main() -> Result<(), postgres::Error> { + /// let mut client = Client::connect("host=localhost user=postgres", NoTls)?; + /// + /// let baz = true; + /// let mut it = client.query_iter("SELECT foo FROM bar WHERE baz = $1", &[&baz])?; + /// + /// while let Some(row) = it.next()? { + /// let foo: i32 = row.get("foo"); + /// println!("foo: {}", foo); + /// } + /// # Ok(()) + /// # } pub fn query_iter( &mut self, query: &T, @@ -65,6 +172,10 @@ impl Client { Ok(QueryIter::new(self.0.query(&statement, params))) } + /// Executes a `COPY FROM STDIN` statement, returning the number of rows created. + /// + /// The `query` argument can either be a `Statement`, or a raw query string. The data in the provided reader is + /// passed along to the server verbatim; it is the caller's responsibility to ensure it uses the proper format. pub fn copy_in( &mut self, query: &T, @@ -81,6 +192,9 @@ impl Client { .wait() } + /// Executes a `COPY TO STDOUT` statement, returning a reader of the resulting data. + /// + /// The `query` argument can either be a `Statement`, or a raw query string. pub fn copy_out( &mut self, query: &T, @@ -94,14 +208,43 @@ impl Client { CopyOutReader::new(stream) } + /// Executes a sequence of SQL statements using the simple query protocol. + /// + /// Statements should be separated by semicolons. If an error occurs, execution of the sequence will stop at that + /// point. The simple query protocol returns the values in rows as strings rather than in their binary encodings, + /// so the associated row type doesn't work with the `FromSql` trait. Rather than simply returning the rows, this + /// method returns a sequence of an enum which indicates either the completion of one of the commands, or a row of + /// data. This preserves the framing between the separate statements in the request. + /// + /// This is a simple convenience method over `simple_query_iter`. + /// + /// # Warning + /// + /// Prepared statements should be use for any query which contains user-specified data, as they provided the + /// functionality to safely imbed that data in the request. Do not form statements via string concatenation and pass + /// them to this method! pub fn simple_query(&mut self, query: &str) -> Result, Error> { self.simple_query_iter(query)?.collect() } + /// Executes a sequence of SQL statements using the simple query protocol. + /// + /// Statements should be separated by semicolons. If an error occurs, execution of the sequence will stop at that + /// point. The simple query protocol returns the values in rows as strings rather than in their binary encodings, + /// so the associated row type doesn't work with the `FromSql` trait. Rather than simply returning the rows, this + /// method returns a sequence of an enum which indicates either the completion of one of the commands, or a row of + /// data. This preserves the framing between the separate statements in the request. + /// + /// # Warning + /// + /// Prepared statements should be use for any query which contains user-specified data, as they provided the + /// functionality to safely imbed that data in the request. Do not form statements via string concatenation and pass + /// them to this method! pub fn simple_query_iter(&mut self, query: &str) -> Result, Error> { Ok(SimpleQueryIter::new(self.0.simple_query(query))) } + /// Begins a new database transaction. pub fn transaction(&mut self) -> Result, Error> { self.simple_query("BEGIN")?; Ok(Transaction::new(self))