Add sync copy_out
This commit is contained in:
parent
2b1cac40c3
commit
793c5f1b87
@ -10,6 +10,7 @@ default = ["runtime"]
|
||||
runtime = ["tokio-postgres/runtime", "tokio", "lazy_static", "log"]
|
||||
|
||||
[dependencies]
|
||||
bytes = "0.4"
|
||||
futures = "0.1"
|
||||
tokio-postgres = { version = "0.3", path = "../tokio-postgres", default-features = false }
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
use bytes::{Buf, Bytes};
|
||||
use futures::stream;
|
||||
use futures::sync::mpsc;
|
||||
use futures::{Async, AsyncSink, Future, Poll, Sink, Stream};
|
||||
use std::io::{self, Read};
|
||||
use std::io::{self, BufRead, Cursor, Read};
|
||||
use std::marker::PhantomData;
|
||||
use tokio_postgres::types::{ToSql, Type};
|
||||
use tokio_postgres::{Error, Row};
|
||||
#[cfg(feature = "runtime")]
|
||||
@ -78,6 +81,30 @@ impl Client {
|
||||
.wait()
|
||||
}
|
||||
|
||||
pub fn copy_out<T>(
|
||||
&mut self,
|
||||
query: &T,
|
||||
params: &[&dyn ToSql],
|
||||
) -> Result<CopyOutReader<'_>, Error>
|
||||
where
|
||||
T: ?Sized + Query,
|
||||
{
|
||||
let statement = query.__statement(self)?;
|
||||
let mut stream = self.0.copy_out(&statement.0, params).wait();
|
||||
|
||||
let cur = match stream.next() {
|
||||
Some(Ok(cur)) => cur,
|
||||
Some(Err(e)) => return Err(e),
|
||||
None => Bytes::new(),
|
||||
};
|
||||
|
||||
Ok(CopyOutReader {
|
||||
stream,
|
||||
cur: Cursor::new(cur),
|
||||
_p: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn batch_execute(&mut self, query: &str) -> Result<(), Error> {
|
||||
self.0.batch_execute(query).wait()
|
||||
}
|
||||
@ -179,3 +206,37 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CopyOutReader<'a> {
|
||||
stream: stream::Wait<tokio_postgres::CopyOut>,
|
||||
cur: Cursor<Bytes>,
|
||||
_p: PhantomData<&'a mut ()>,
|
||||
}
|
||||
|
||||
impl<'a> Read for CopyOutReader<'a> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let b = self.fill_buf()?;
|
||||
let len = usize::min(buf.len(), b.len());
|
||||
buf[..len].copy_from_slice(&b[..len]);
|
||||
self.consume(len);
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BufRead for CopyOutReader<'a> {
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
||||
if self.cur.remaining() == 0 {
|
||||
match self.stream.next() {
|
||||
Some(Ok(cur)) => self.cur = Cursor::new(cur),
|
||||
Some(Err(e)) => return Err(io::Error::new(io::ErrorKind::Other, e)),
|
||||
None => {}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Buf::bytes(&self.cur))
|
||||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) {
|
||||
self.cur.advance(amt);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use std::io::Read;
|
||||
use tokio_postgres::types::Type;
|
||||
use tokio_postgres::NoTls;
|
||||
|
||||
@ -171,3 +172,28 @@ fn copy_in() {
|
||||
assert_eq!(rows[1].get::<_, i32>(0), 2);
|
||||
assert_eq!(rows[1].get::<_, &str>(1), "timothy");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_out() {
|
||||
let mut client = Client::connect("host=localhost port=5433 user=postgres", NoTls).unwrap();
|
||||
|
||||
client
|
||||
.batch_execute(
|
||||
"
|
||||
CREATE TEMPORARY TABLE foo (id INT, name TEXT);
|
||||
|
||||
INSERT INTO foo (id, name) VALUES (1, 'steven'), (2, 'timothy');
|
||||
",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut reader = client
|
||||
.copy_out("COPY foo (id, name) TO STDOUT", &[])
|
||||
.unwrap();
|
||||
let mut s = String::new();
|
||||
reader.read_to_string(&mut s).unwrap();
|
||||
|
||||
assert_eq!(s, "1\tsteven\n2\ttimothy\n");
|
||||
|
||||
client.batch_execute("SELECT 1").unwrap();
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use std::io::Read;
|
||||
use tokio_postgres::types::{ToSql, Type};
|
||||
use tokio_postgres::{Error, Row};
|
||||
|
||||
use crate::{Client, Query, Statement};
|
||||
use crate::{Client, CopyOutReader, Query, Statement};
|
||||
|
||||
pub struct Transaction<'a> {
|
||||
client: &'a mut Client,
|
||||
@ -86,6 +86,17 @@ impl<'a> Transaction<'a> {
|
||||
self.client.copy_in(query, params, reader)
|
||||
}
|
||||
|
||||
pub fn copy_out<T>(
|
||||
&mut self,
|
||||
query: &T,
|
||||
params: &[&dyn ToSql],
|
||||
) -> Result<CopyOutReader<'_>, Error>
|
||||
where
|
||||
T: ?Sized + Query,
|
||||
{
|
||||
self.client.copy_out(query, params)
|
||||
}
|
||||
|
||||
pub fn batch_execute(&mut self, query: &str) -> Result<(), Error> {
|
||||
self.client.batch_execute(query)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user