Skip to content

Improve TxManager API: Pass transaction as parameter instead of global state #197

@firov

Description

@firov

Current YOJ TxManager API uses global state via Tx.Current.get() to access active transaction. This creates several issues:

  • Implicit contract: Methods accept Runnable/Supplier but don't explicitly pass transaction object
  • Hidden dependency: Code accesses tables through global state
  • Poor discoverability: Not obvious from method signature that transaction is available
  • Testing complexity: Global state makes unit testing harder

Current Implementation

// Usage - implicit transaction access
var result = txManager.readOnly(() -> {
    return dao.table(SomeTable.class).find(id); // Uses Tx.Current.get() internally
});

Proposed Solution

Add overloads accepting [Function<RepositoryTransaction, T>]

// In TxManager
default <T> T tx(Function<RepositoryTransaction, T> function) {
    return tx(() -> function.apply(Tx.Current.get().getRepositoryTransaction()));
}

default void tx(Consumer<RepositoryTransaction> consumer) {
    tx(tx -> {
        consumer.accept(tx);
        return null;
    });
}

default <T> T readOnly(Function<RepositoryTransaction, T> function) {
    return readOnly().run(() -> function.apply(Tx.Current.get().getRepositoryTransaction()));
}

Usage After Changes

var result = txManager.readOnly(tx -> {
    return tx.someTable().find(id);
});

Benefits

  • Explicit contract: Clear from signature that transaction is provided
  • No magic: No need to know about Tx.Current internals
  • Better IDE support: Type inference and navigation work properly
  • Testability: Can pass mock transaction for testing
  • Backward compatible: Old methods remain, new ones are optional

Migration

Change is backward compatible. Old code continues working:

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions