Support Nested Transactions / Savepoints #19346
Labels
domain/client
Issue in the "Client" domain: Prisma Client, Prisma Studio etc.
kind/feature
A request for a new feature.
tech/engines
Issue for tech Engines.
tech/typescript
Issue for tech TypeScript.
topic: interactiveTransactions
topic: nested transactions
topic: savepoint
Problem
Nested Transactions are useful in many cases. They are implemented in all other serious database query systems: (TypeORM, Rail's ActiveRecord, Django ORM, Laravel's Eloquent ORM, Elixir Phoenixs Ecto, Spring etc.)
A common use case is using nested transactions to run tests within their own transaction. (Rails, Django, Phoenix and possibly others default to this behaviour).
Other use cases include more complex business logic, where partial rollback is necessary.
Many users of Prisma have run into this problem (1 2 3 4 5), and it has inspired a number of workarounds (1 2 3 4 5).
Suggested solution
Most databases implement nested transactions with "Save points". For example, see the PostgresSQL API:
Application code usually do not care about whether or not the transaction it's about to start is nested within another transaction. In the case of running transactional tests, all application code transactions should actually be nested transactions, but it should not need to require changes to the application code.
Thus, I propose either that prisma.$transaction is changed to run nested transactions if a transaction has already been started, or to crease a new function prisma.$possibly_nested_transaction that will nest transactions automatically.
As far as I can tell it's not possible to implement this via the prisma extension system, as we have to proxy all calls to the prisma clients to make sure no new outer transactions are started.
Here is an (untested, possibly buggy) "extension" to the prismaClient to implement this feature for PostgreSQL:
Alternatives
The Prisma extension
callback-free-itx
implements an imperative API to start and stop transactions without wrapping them in a function. This an attempt at allowing transactional tests, however, it will not work with tests relying on transactions in the application code. It's mostly a workaround for the fact that some test runners does have the feature to wrap each test within a function. Eg:Thus I believe it should be implemented in the test runners, not by Prisma.
Additional context
The issue of running transactional tests have been mentioned numerous times in this repo. Mocking database calls (as it proposed here) makes tests faster, but often, its the actual database calls that are the most important thing to test. There's a reason why serious application frameworks default to not mock the database. I've tried to do so in the past, but in most cases it simply leads to tests that don't actually test anything).
As I began investigating this, I realised that another team within my organisation had run into exactly this issue a year ago in another project that uses Prisma. Speaking with the programmers on the team, they advised me not to use Prisma for future projects.
The text was updated successfully, but these errors were encountered: