Repository: sfackler/rust-postgres (rust)

Issue:
Get all statemet columns
I try to get all statement's columns for logging, but field `columns` is private. I use `simple_query` method because working with `pgbouncer`.

```rust
use postgres::{Client, SimpleQueryMessage, No};
use native_tls::{Certificate, TlsConnector};
use postgres_native_tls::MakeTlsConnector;
use std::fs;

fn main() {
    let mut client = Client::connect("...", NoTls).unwrap();

    let messages = client.simple_query("SELECT foo, bar FROM baz;").unwrap();
    match messages.first() {
        Some(SimpleQueryMessage::Row(msg)) => {
            // field "columns" of struct "tokio_postgres::row::SimpleQueryRow" is private
            println!("{}", msg.columns.join(" ")) // TODO print all columns
        },
        _ => (),
    }
}
```

Pull request description:
expose SimpleQueryRow's column names
resolves #650.

Added `SimpleColumn` type in order to ensure further extensibility.

Patch:
diff --git a/tokio-postgres/src/row.rs b/tokio-postgres/src/row.rs
index 842216ad..e3ed696c 100644
--- a/tokio-postgres/src/row.rs
+++ b/tokio-postgres/src/row.rs
@@ -1,6 +1,7 @@
 //! Rows.
 
 use crate::row::sealed::{AsName, Sealed};
+use crate::simple_query::SimpleColumn;
 use crate::statement::Column;
 use crate::types::{FromSql, Type, WrongType};
 use crate::{Error, Statement};
@@ -188,16 +189,25 @@ impl Row {
     }
 }
 
+impl AsName for SimpleColumn {
+    fn as_name(&self) -> &str {
+        self.name()
+    }
+}
+
 /// A row of data returned from the database by a simple query.
 pub struct SimpleQueryRow {
-    columns: Arc<[String]>,
+    columns: Arc<[SimpleColumn]>,
     body: DataRowBody,
     ranges: Vec<Option<Range<usize>>>,
 }
 
 impl SimpleQueryRow {
     #[allow(clippy::new_ret_no_self)]
-    pub(crate) fn new(columns: Arc<[String]>, body: DataRowBody) -> Result<SimpleQueryRow, Error> {
+    pub(crate) fn new(
+        columns: Arc<[SimpleColumn]>,
+        body: DataRowBody,
+    ) -> Result<SimpleQueryRow, Error> {
         let ranges = body.ranges().collect().map_err(Error::parse)?;
         Ok(SimpleQueryRow {
             columns,
@@ -206,6 +216,11 @@ impl SimpleQueryRow {
         })
     }
 
+    /// Returns information about the columns of data in the row.
+    pub fn columns(&self) -> &[SimpleColumn] {
+        &self.columns
+    }
+
     /// Determines if the row contains no values.
     pub fn is_empty(&self) -> bool {
         self.len() == 0
diff --git a/tokio-postgres/src/simple_query.rs b/tokio-postgres/src/simple_query.rs
index 82ac3566..ade2e1d6 100644
--- a/tokio-postgres/src/simple_query.rs
+++ b/tokio-postgres/src/simple_query.rs
@@ -14,6 +14,22 @@ use std::pin::Pin;
 use std::sync::Arc;
 use std::task::{Context, Poll};
 
+/// Information about a column of a single query row.
+pub struct SimpleColumn {
+    name: String,
+}
+
+impl SimpleColumn {
+    pub(crate) fn new(name: String) -> SimpleColumn {
+        SimpleColumn { name }
+    }
+
+    /// Returns the name of the column.
+    pub fn name(&self) -> &str {
+        &self.name
+    }
+}
+
 pub async fn simple_query(client: &InnerClient, query: &str) -> Result<SimpleQueryStream, Error> {
     debug!("executing simple query: {}", query);
 
@@ -56,7 +72,7 @@ pin_project! {
     /// A stream of simple query results.
     pub struct SimpleQueryStream {
         responses: Responses,
-        columns: Option<Arc<[String]>>,
+        columns: Option<Arc<[SimpleColumn]>>,
         #[pin]
         _p: PhantomPinned,
     }
@@ -86,10 +102,11 @@ impl Stream for SimpleQueryStream {
                 Message::RowDescription(body) => {
                     let columns = body
                         .fields()
-                        .map(|f| Ok(f.name().to_string()))
+                        .map(|f| Ok(SimpleColumn::new(f.name().to_string())))
                         .collect::<Vec<_>>()
                         .map_err(Error::parse)?
                         .into();
+
                     *this.columns = Some(columns);
                 }
                 Message::DataRow(body) => {


Test patch:
diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs
index c367dbea..c0b4bf20 100644
--- a/tokio-postgres/tests/test/main.rs
+++ b/tokio-postgres/tests/test/main.rs
@@ -282,6 +282,8 @@ async fn simple_query() {
     }
     match &messages[2] {
         SimpleQueryMessage::Row(row) => {
+            assert_eq!(row.columns().get(0).map(|c| c.name()), Some("id"));
+            assert_eq!(row.columns().get(1).map(|c| c.name()), Some("name"));
             assert_eq!(row.get(0), Some("1"));
             assert_eq!(row.get(1), Some("steven"));
         }
@@ -289,6 +291,8 @@ async fn simple_query() {
     }
     match &messages[3] {
         SimpleQueryMessage::Row(row) => {
+            assert_eq!(row.columns().get(0).map(|c| c.name()), Some("id"));
+            assert_eq!(row.columns().get(1).map(|c| c.name()), Some("name"));
             assert_eq!(row.get(0), Some("2"));
             assert_eq!(row.get(1), Some("joe"));
         }