Hello, I have a question: Has anyone tried to set ...
# orm-help
a
Hello, I have a question: Has anyone tried to set up database transaction testing with prisma? I have a setup that only half works where I pass a function as a parameter into a function that executes
prisma.$transaction
, but the problem is that all subsequent queries need to be transaction-aware (and so needs to use the prisma object provided by the
$transaction
callback). This means I need to control the prisma object being passed to my backend functions so that instead of the normal client, they get the transaction-aware client. Is there some clever way to do this? The docs recommend mocking but I would strongly prefer transaction-rollback testing my backend functions. Any recommendations from the community? Thank you šŸ™
āœ… 1
a
Hey Austin! Great name šŸ™‚. I don’t have any examples of rollback-based testing, but it should be possible with the interactive transactions preview feature. You would start a transaction at the beginning of your test and throw an error at the end to force the rollback. I don’t see any way around passing the ā€œtransaction-aware clientā€ to your various functions, though. If you land on something you like, please share it with us!
a
Hey, great name too šŸ˜† so I have landed on something I don’t love but works. I’m using playwright. I create a singleton class called
db
with a
db.prisma
singleton and a
db.set
function. Inside my playwright test function I call
withData
and that function is defined as follows (which is heavily inspired by the prisma docs):
Copy code
export async function withData(fn: () => Promise<void>) {
  try {
    await new PrismaClient().$transaction(async (prisma) => {
      db.set(prisma)
      await fn(prisma)
      throw new Error('rollback trigger')
    })
  } catch (err: any) {
    if (err.message != 'rollback trigger') throw err
  }
It’s a bit like using a Singleton class as a poor-mans IOC Dependency Injection, since in my code I’m now calling
db.prisma.user.create
, etc, and so don’t have to worry about receiving a prisma param for every function I write. And it does solve the transaction-aware prisma client problem when I’m calling just domain functions. So far so good, but, when I try to spin up a dev server and hit an endpoint, I’m creating another client in that other process that is not transaction aware. I also tried `prisma.$executeRaw`Begin;`` and
Rollback;
instead of the
$transaction
call, which I think would’ve worked as well, but it also doesn’t solve the separate process dev server problem. I know other frameworks would have to deal with this, like Rails and Phoenix. I’m most familiar with Ecto, the Elixir ORM-like, which solves this on the adapter level. So, as a peer to other db adapters like pg, mysql, mongo, etc., they have a sqlsandbox, and I think they somehow only provide clients that are (a) transaction-aware, and (b) can somehow read each other’s transaction writes and/or are really just a single client to begin with? I need to investigate further. (I really want to figure this out bc I’m in love with (a) the power of db-aware service-layer tests, and (b) the speed with which transaction-rollback tests achieve (a). I have read yalls docs on the docker database approach. Have done a thing like that before and it’s fine enough, but it can get really slow at scale to try and reset the docker db per test or chunk of tests, and ā€œundoingā€ the changes in an afterEach is a sad and tedious world šŸ˜† )
Here’s the ecto docs I’m referring to, for reference: https://hexdocs.pm/ecto_sql/Ecto.Adapters.SQL.Sandbox.html