Skuld.Effects.DBTransaction (skuld v0.1.12)

View Source

Effect for database transactions with automatic commit/rollback semantics.

Operations

  • transact(comp) - Run a computation inside a transaction
  • rollback(reason) - Explicitly roll back the current transaction

Behavior

Within a transact block:

  • Normal completion: Transaction commits
  • Throw: Transaction rolls back, throw propagates
  • Suspend: Transaction rolls back, suspend propagates
  • Explicit rollback: Transaction rolls back, returns {:rolled_back, reason}

Handlers

  • DBTransaction.Ecto.with_handler/2,3 - Ecto-based transactions
  • DBTransaction.Noop.with_handler/1 - No-op for testing

Example

alias Skuld.Comp
alias Skuld.Effects.DBTransaction
alias Skuld.Effects.DBTransaction.Ecto, as: EctoTx

comp do
  result <- DBTransaction.transact(comp do
    user <- create_user(attrs)

    if invalid?(user) do
      _ <- DBTransaction.rollback({:invalid_user, user})
    end

    return(user)
  end)

  return(result)
end
|> EctoTx.with_handler(MyApp.Repo)
|> Comp.run!()

Rollback on Throw

comp do
  result <- DBTransaction.transact(comp do
    _ <- Throw.throw(:something_went_wrong)
    return(:never_reached)
  end)
  return(result)
end
|> EctoTx.with_handler(MyApp.Repo)
|> Throw.with_handler()
|> Comp.run!()
# Transaction is rolled back, returns the throw error

Nested Transactions

Nested transact calls create savepoints (if supported by the database):

comp do
  result <- DBTransaction.transact(comp do
    _ <- insert_parent()

    inner_result <- DBTransaction.transact(comp do
      _ <- insert_child()
      return(:inner_done)
    end)

    return({:outer_done, inner_result})
  end)
  return(result)
end
|> EctoTx.with_handler(MyApp.Repo)
|> Comp.run!()

Summary

Functions

Explicitly roll back the current transaction.

Get the effect signature for handler installation.

Run a computation inside a database transaction.

Functions

rollback(reason)

@spec rollback(term()) :: Skuld.Comp.Types.computation()

Explicitly roll back the current transaction.

Must be called within a transact block. Returns {:rolled_back, reason} after the transaction is rolled back.

Example

comp do
  result <- DBTransaction.transact(comp do
    user <- create_user(attrs)

    if should_abort?(user) do
      _ <- DBTransaction.rollback({:aborted, user.id})
    end

    return(user)
  end)

  return(result)
end

sig()

Get the effect signature for handler installation.

transact(comp)

Run a computation inside a database transaction.

The inner computation will be executed within a transaction scope. On normal completion, the transaction commits. On throw, suspend, or explicit rollback, the transaction rolls back.

Parameters

  • comp - The computation to run inside the transaction

Returns

A computation that returns the result of the inner computation, or {:rolled_back, reason} if explicitly rolled back.

Example

comp do
  result <- DBTransaction.transact(comp do
    user <- insert_user(attrs)
    order <- insert_order(user, order_attrs)
    return({user, order})
  end)

  # result is {user, order} if successful
  return(result)
end
|> DBTransaction.Ecto.with_handler(MyApp.Repo)
|> Comp.run!()