# transactioncheck

A Go linter that detects database operations leaking outside transaction boundaries. Built with the [[go-analysis-framework]] after the author shipped a transaction bug to production.

## What it catches

In codebases using callback-based transactions with repository patterns:

```go
return s.repo.Transaction(ctx, func(tx models.Repo) error {
    user, err := s.repo.GetUser(ctx, userID) // FLAGGED: uses s.repo, not tx
    return tx.SaveUser(ctx, user)
})
```

The linter flags uses of the outer repository (`s.repo`) inside transaction callbacks where the transaction parameter (`tx`) should be used instead.

Two violation types:
- Direct method calls on the outer repo
- Passing the outer repo to helper functions instead of `tx`

## How it works

1. AST walking filtered to `*ast.CallExpr` nodes
2. Identifies `Transaction` method calls on repository interfaces
3. Captures the callback's `tx` parameter as a `types.Object`
4. Scans the callback body for references to the outer repo
5. Recursively analyzes helper functions that receive `tx`

The `types.Object` comparison handles variable shadowing correctly — two identifiers sharing the same object point to the same variable.

## Usage

Run standalone:

```bash
go install github.com/leonhfr/transactioncheck/cmd/transactioncheck@latest
transactioncheck ./...
```

Or via mise task:

```toml
[tasks.transactioncheck]
run = 'bin/transactioncheck ./...'
```

## Testing

Uses `analysistest` with `// want` comments:

```go
_ = s.repo.GetUser( // want "using non-transaction repo..."
    ctx, "123",
)
```

## Limitations

- Requires consistent repository interface naming (configurable)
- Only tracks violations within the same package (no cross-package analysis)
- Recursive analysis may miss violations through interfaces

---

Repo: https://github.com/leonhfr/transactioncheck
