Skip to content

Commit f3777be

Browse files
author
Darren Tsung
committed
Add a TransactionBuilder struct
The TransactionBuilder is useful when trying to create a Transaction around a future which takes ownership of the client. See doc comment for more details.
1 parent 04bd98e commit f3777be

2 files changed

Lines changed: 73 additions & 1 deletion

File tree

tokio-postgres/src/lib.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,17 @@ impl Client {
116116
// FIXME error type?
117117
T::Error: From<Error>,
118118
{
119-
Transaction(proto::TransactionFuture::new(self.0.clone(), future))
119+
self.transaction_builder().build(future)
120+
}
121+
122+
/// Creates a TransactionBuilder, which can later be used to create
123+
/// a Transaction around a future.
124+
///
125+
/// Use this when Client is moved into the future being built.
126+
/// For example, when executing multiple statements that depend
127+
/// on the previous statement's result.
128+
pub fn transaction_builder(&self) -> TransactionBuilder {
129+
TransactionBuilder(self.0.clone())
120130
}
121131

122132
pub fn batch_execute(&mut self, query: &str) -> BatchExecute {
@@ -333,6 +343,19 @@ impl Row {
333343
}
334344
}
335345

346+
pub struct TransactionBuilder(proto::Client);
347+
348+
impl TransactionBuilder {
349+
pub fn build<T>(self, future: T) -> Transaction<T>
350+
where
351+
T: Future,
352+
// FIXME error type?
353+
T::Error: From<Error>,
354+
{
355+
Transaction(proto::TransactionFuture::new(self.0, future))
356+
}
357+
}
358+
336359
#[must_use = "futures do nothing unless polled"]
337360
pub struct Transaction<T>(proto::TransactionFuture<T, T::Item, T::Error>)
338361
where

tokio-postgres/tests/test.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,3 +692,52 @@ fn copy_out() {
692692
).unwrap();
693693
assert_eq!(&data[..], b"1\tjim\n2\tjoe\n");
694694
}
695+
696+
#[test]
697+
fn transaction_builder_around_moved_client() {
698+
let _ = env_logger::try_init();
699+
let mut runtime = Runtime::new().unwrap();
700+
701+
let (mut client, connection) = runtime
702+
.block_on(tokio_postgres::connect(
703+
"postgres://postgres@localhost:5433".parse().unwrap(),
704+
TlsMode::None,
705+
)).unwrap();
706+
let connection = connection.map_err(|e| panic!("{}", e));
707+
runtime.handle().spawn(connection).unwrap();
708+
709+
let transaction_builder = client.transaction_builder();
710+
let work = future::lazy(move || {
711+
let execute =
712+
client.batch_execute(
713+
"CREATE TEMPORARY TABLE transaction_foo (
714+
id SERIAL,
715+
name TEXT
716+
)");
717+
718+
execute.and_then(move |_| {
719+
client
720+
.prepare("INSERT INTO transaction_foo (name) VALUES ($1), ($2)")
721+
.map(|statement| (client, statement))
722+
})
723+
}).and_then(|(mut client, statement)| {
724+
client
725+
.query(&statement, &[&"jim", &"joe"])
726+
.collect()
727+
.map(|_res| client)
728+
});
729+
730+
let transaction = transaction_builder.build(work);
731+
let mut client = runtime.block_on(transaction).unwrap();
732+
733+
let data = runtime
734+
.block_on(
735+
client
736+
.prepare("COPY transaction_foo TO STDOUT")
737+
.and_then(|s| client.copy_out(&s, &[]).concat2()),
738+
).unwrap();
739+
assert_eq!(&data[..], b"1\tjim\n2\tjoe\n");
740+
741+
drop(client);
742+
runtime.run().unwrap();
743+
}

0 commit comments

Comments
 (0)