Skip to content

Commit

Permalink
StandaloneTransaction
Browse files Browse the repository at this point in the history
  • Loading branch information
aljazerzen committed Jan 10, 2025
1 parent 1e4f496 commit 2c68f31
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 92 deletions.
2 changes: 1 addition & 1 deletion edgedb-tokio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ edgedb-protocol = { path = "../edgedb-protocol", version = "0.6.0", features = [
] }
edgedb-errors = { path = "../edgedb-errors", version = "0.4.1" }
edgedb-derive = { path = "../edgedb-derive", version = "0.5.1", optional = true }
tokio = { version = "1.15", features = ["net", "time", "sync", "macros"] }
tokio = { version = "1.15", features = ["net", "time", "sync", "macros", "rt"] }
bytes = "1.5.0"
scram = { version = "0.7", package = "scram-2" }
serde = { version = "1.0", features = ["derive"] }
Expand Down
2 changes: 1 addition & 1 deletion edgedb-tokio/examples/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ async fn main() -> anyhow::Result<()> {
env_logger::init();
let conn = edgedb_tokio::create_client().await?;
let val = conn
.transaction(|mut transaction| async move {
.within_transaction(|mut transaction| async move {
transaction
.query_required_single::<i64, _>(
"SELECT (UPDATE Counter SET { value := .value + 1}).value LIMIT 1",
Expand Down
2 changes: 1 addition & 1 deletion edgedb-tokio/examples/transaction_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async fn main() -> anyhow::Result<()> {
env_logger::init();
let conn = edgedb_tokio::create_client().await?;
let res = conn
.transaction(|mut transaction| async move {
.within_transaction(|mut transaction| async move {
let val = transaction
.query_required_single::<i64, _>(
"
Expand Down
62 changes: 54 additions & 8 deletions edgedb-tokio/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::raw::{Options, PoolState, Response};
use crate::raw::{Pool, QueryCapabilities};
use crate::state::{AliasesDelta, ConfigDelta, GlobalsDelta};
use crate::state::{AliasesModifier, ConfigModifier, Fn, GlobalsModifier};
use crate::transaction::{transaction, Transaction};
use crate::transaction::{RetryingTransaction, StandaloneTransaction};
use crate::ResultVerbose;

/// The EdgeDB Client.
Expand Down Expand Up @@ -374,13 +374,18 @@ impl Client {
}
}

/// Execute a transaction
/// Execute a transaction and retry.
///
/// Transaction body must be encompassed in the closure. The closure **may
/// be executed multiple times**. This includes not only database queries
/// but also executing the whole function, so the transaction code must be
/// prepared to be idempotent.
///
/// # Commit and rollback
///
/// When the closure returns, the transaction is commit. Transaction cannot
/// be rolled back explicitly.
///
/// # Returning custom errors
///
/// See [this example](https://github.com/edgedb/edgedb-rust/blob/master/edgedb-tokio/examples/transaction_errors.rs)
Expand All @@ -397,24 +402,65 @@ impl Client {
/// # Example
///
/// ```rust,no_run
/// # async fn transaction() -> Result<(), edgedb_tokio::Error> {
/// # async fn main_() -> Result<(), edgedb_tokio::Error> {
/// let conn = edgedb_tokio::create_client().await?;
/// let val = conn.transaction(|mut tx| async move {
/// let val = conn.within_transaction(|mut tx| async move {
/// tx.query_required_single::<i64, _>("
/// WITH C := UPDATE Counter SET { value := .value + 1}
/// SELECT C.value LIMIT 1
/// ", &()
/// ", &()
/// ).await
/// }).await?;
/// # Ok(())
/// # }
/// ```
pub async fn transaction<T, B, F>(&self, body: B) -> Result<T, Error>
pub async fn within_transaction<T, B, F>(&self, body: B) -> Result<T, Error>
where
B: FnMut(Transaction) -> F,
B: FnMut(RetryingTransaction) -> F,
F: Future<Output = Result<T, Error>>,
{
transaction(&self.pool, self.options.clone(), body).await
crate::transaction::run_and_retry(&self.pool, self.options.clone(), body).await
}

/// Start a transaction.
///
/// Returns [StandaloneTransaction] which implements [crate::QueryExecutor] and can
/// be used to execute queries within the transaction.
///
/// The transaction will never retry failed queries, even if the database signals that the
/// query should be retried. For this reason, it is recommended to use [Client::within_transaction]
/// when possible.
///
/// <div class="warning">
/// Transactions can fail for benign reasons and should always handle that case gracefully.
/// `StandaloneTransaction` does not provide any retry mechanisms, so this responsibility falls
/// onto the user. For example, even only two select queries in a transaction can fail due to
/// concurrent modification of the database.
/// </div>
///
/// # Commit and rollback
///
/// To commit the changes made during the transaction,
/// [commit](crate::StandaloneTransaction::commit) method must be called, otherwise the
/// transaction will roll back when [StandaloneTransaction] is dropped.
///
/// # Example
///
/// ```rust,no_run
/// # async fn main_() -> Result<(), edgedb_tokio::Error> {
/// let conn = edgedb_tokio::create_client().await?;
/// let mut tx = conn.transaction().await?;
/// tx.query_required_single::<i64, _>("
/// WITH C := UPDATE Counter SET { value := .value + 1}
/// SELECT C.value LIMIT 1
/// ", &()
/// ).await;
/// tx.commit().await;
/// # Ok(())
/// # }
/// ```
pub async fn transaction(&self) -> Result<StandaloneTransaction, Error> {
crate::transaction::start(&self.pool, self.options.clone()).await
}

/// Returns client with adjusted options for future transactions.
Expand Down
2 changes: 1 addition & 1 deletion edgedb-tokio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ pub use errors::Error;
pub use options::{RetryCondition, RetryOptions, TransactionOptions};
pub use query_executor::{QueryExecutor, ResultVerbose};
pub use state::{ConfigDelta, GlobalsDelta};
pub use transaction::Transaction;
pub use transaction::{RetryingTransaction, StandaloneTransaction, Transaction};

/// The ordered list of project filenames supported.
pub const PROJECT_FILES: &[&str] = &["gel.toml", "edgedb.toml"];
Expand Down
4 changes: 2 additions & 2 deletions edgedb-tokio/src/query_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub trait QueryExecutor: Sized {
A: QueryArgs,
R: QueryResult + Send;

/// see [Client::query_with_warnings]
/// see [Client::query_verbose]
fn query_verbose<R, A>(
self,
query: impl AsRef<str> + Send,
Expand Down Expand Up @@ -171,7 +171,7 @@ impl QueryExecutor for &Client {
}
}

impl QueryExecutor for &mut Transaction {
impl<T: std::ops::DerefMut<Target = Transaction>> QueryExecutor for &mut T {
fn query<R, A>(
self,
query: impl AsRef<str> + Send,
Expand Down
Loading

0 comments on commit 2c68f31

Please sign in to comment.