Closed
Description
This would allow for reusable functions that query for data, but can be used on a connection or a transaction.
A basic idea would be the following
trait ConnectionLike {
fn batch_execute(self, query: &str) -> Box<Future<Item = Self, Error = (Error, Self)> + Send>;
fn execute(self, query: &str) -> Box<Future<Item = Self, Error = (Error, Self)> + Send>;
fn prepare(self, query: &str) -> Box<Future<Item = (Statement, Self), Error = (Error, Self)> + Send>;
fn execute(self, statement: &Statement, params: &[&ToSql]) -> Box<Future<Item = (u64, Self), Error = (Error, Self)> + Send>;
fn query(self, statement: &Statement, params: &[&ToSql]) -> Box<Future<Item = Row, State = Self, Error = Error> + Send>;
}
impl ConnectionLike for Connection {
...
}
impl ConnectionLike for Transaction {
...
}
Which could allow for things like the following. This example function, fetch_events
could be called in production with a Connection, but could be called in tests with a Transaction, allowing for easy rollbacks.
fn fetch_events<C: ConnectionLike>(conn: C) -> impl Future<Item = (Vec<Event>, C), Error = (Error, C)> {
conn.prepare("SELECT evt.id, evt.title FROM events AS evt")
.and_then(move |(s, conn)| {
conn.query(&s, &[&id])
.map(move |row| Event {
id: row.get(0),
title: row.get(1),
})
.collect()
})
}
// in the test (this could likely be extracted into a boilerplate function)
connection
.transaction()
.and_then(|transaction| {
fetch_events(transaction)
.map_err(|(error, transaction)| {
transaction.rollback().map(|connection| (error, connection))
})
.map(|(events, transaction)| {
transaction.rollback().map(|connection| (events, connection))
})
// in the production code
fetch_events(connection)
Metadata
Metadata
Assignees
Labels
No labels