2 unstable releases
Uses old Rust 2015
0.2.1 | Jun 23, 2017 |
---|---|
0.2.0 |
|
0.1.0 | Jun 6, 2017 |
#2061 in Rust patterns
508 downloads per month
Used in 2 crates
36KB
1K
SLoC
Transaction
An zero cost transaction abstraction library. This crate provide the ways to abstract and compinate transactions. Combinated comptations are run under a transaction. Not only it can be composed run under a transaction, it also requires computations are composed and run under a transaction.
To run the transactions, use crates like transaction-stm
or transaction-diesel
lib.rs
:
Zero-cost transaction abstraction in Rust
This crate abstracts over transactions like STM, SQL transactions and so on. It is composable via combinators and does DI of transactions.
The basic idea is representing contracts of "this computation must be run"
as types. The trait Transaction
represents o sequence of computation that
must be run under a transaction. And transactions are composable
(sequencable) using then
, and_then
, or_else
, hence you can use it
like values wrapped in Result
.Since it represents computation to be run
in data, some types respond to control operators are provided: abort
for
?
, repeat
for for
, loop_fn
for loop
and branch
for (join point
of) if
and so on. As all the combinators have its own result type, no
dispatches are done at execution time thus it is zero-cost.
Another feature is it does DI of transaction. For database transaction, it means it injects DB connection from the context.
Examples
extern crate transaction;
use self::transaction::prelude::*;
// Since current rust doesn't support `impl Trait`, you need to make a
// trait box
// to return a trait value from a function.
type BoxTx<'a, T> = Box<Transaction<
Ctx = FooConnection,
Item = T,
Err =FooError>
+ 'a>;
fn find_user<'a>(id: i64) -> BoxTx<'a, Option<User>> {
// connection is inejected from the context
with_ctx(move |cn: &mut FooConnection| {
// ..
# let _ = (id, cn);
# unimplemented!()
}).boxed()
}
fn update_user<'a>(id: i64, name: &'a str) -> BoxTx<'a, Option<()>> {
with_ctx(move |cn: &mut FooConnection| {
// ..
# let _ = (id, cn, name);
# unimplemented!()
}).boxed()
}
fn update_find_user<'a>(id: i64, name: &'a str) -> BoxTx<'a, Option<User>> {
update_user(id, name)
// transaction can be composed using `and_then`
.and_then(move |ret| match ret {
None =>
// to return a leaf transaction, use `ok`, `err` or `result`
ok(None)
// to return from a branch (or, to match types at join
// point), use `branch` API
.branch()
// use `first` in the first arm of the brnach
.first(),
Some(()) => find_user(id)
.branch()
// use `second` in the second arm of the brnach
.second(),
})
// finally, box it to return `BoxTx`.
.boxed()
}