Rust Transaction Management
TeaQL Rust plans object-graph mutations in the runtime and delegates concrete transaction execution to the registered data-service provider.
entity.audit_as(...).save(&ctx)
-> validate and plan graph mutation
-> require provider transaction capability
-> execute graph operations
-> commit on success or roll back on failure
Transaction Boundary
A graph save may create or update several related rows. It must not silently continue with partial results when a child mutation fails.
Application code declares the business audit intent:
order
.audit_as("Create customer order and line items")
.save(&ctx)
.await?;
The provider supplies the database transaction capability. If the selected provider/runtime assembly cannot satisfy the required boundary, treat the save as unsupported rather than assuming atomicity.
Current Provider Boundary
Transaction behavior is implemented below TeaQL's data-service traits. Current relational provider crates are:
teaql-provider-postgres;teaql-provider-mysql;teaql-provider-sqlite.
Historical pages may mention teaql-provider-sqlx-* or a standalone
teaql-provider-rusqlite. Those are not the current provider crate names.
MemoryRepository is useful for fast tests, but it must not be used as proof of
the rollback and isolation behavior of a production relational provider.
What the Application Owns
The application still owns:
- correct provider registration and configuration;
- request/service transaction composition beyond one graph save;
- retry and idempotency policy;
- database isolation and timeout decisions;
- verification that audit identity is present;
- tests for rollback, concurrency, and optimistic locking.
Do not wrap a failed graph save in a blind retry if the operation is not idempotent.
Rollback Test
For each production provider, write an integration test that:
- Creates a parent and at least two child mutations.
- Makes the final child violate a checker or database constraint.
- Saves the graph with a concrete
audit_asdescription. - Confirms the operation returns an error.
- Opens a new query/connection boundary.
- Confirms that the parent and earlier child were not partially committed.
- Inspects audit/log behavior for the failed operation.
Use generated entity methods from the target workspace; do not copy guessed method names into the test.
Existing Transaction Composition
When a business operation combines several independent saves, verify whether
the provider/runtime exposes an application transaction scope that keeps them
atomic. Do not assume that two sequential save calls share one transaction
merely because they use the same UserContext.
Document the exact transaction API from the runtime version in use and add a rollback test covering the complete use case.
Failure Checklist
| Symptom | Check |
|---|---|
| Partial data after child failure | Provider transaction capability, application transaction composition, and test isolation. |
| Save rejected before SQL | Checker failure or missing audit intent. |
| Deadlock or timeout | Transaction scope, operation order, provider pool, database locks, and retry policy. |
| Optimistic-lock conflict | Entity version and whether stale objects are being retried unsafely. |
| Works in memory, fails on database | Provider-specific constraints, types, transactions, and concurrency. |