question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Clarify when Prisma queries are run (PrismaPromise behavior)

See original GitHub issue

@Sytten brought up a good point in Slack that we don’t really talk about when queries are executed.

In this example:

import { User } from '@prisma/client'

export default async (app: Application, { id }: DeleteInput): Promise<User> => {
  const operations: Promise<any>[] = []

  // Delete onboarding
  operations.push(app.prisma.onboarding.deleteMany({ where: { userId: id } }))

  // Delete availability application
  const availabilityApp = await app.models.availabilityApp.findOne({ userId: id })

  if (availabilityApp) {
    operations.push(
      app.prisma.availabilityTemplate.deleteMany({
        where: { appId: availabilityApp.id },
      }),
      app.prisma.availabilityApp.delete({ where: { id: availabilityApp.id } })
    )
  }

  // Delete user
  const user = await app.prisma.user.findOne({ where: { id } })
  operations.push(app.prisma.user.delete({ where: { id } }))

  // Execute all operations
  await app.prisma.transaction(operations)
  return user!
}

You might expect the operations to run in the order that they appear, but this is not the case. They run more like this:

await app.models.availabilityApp.findOne({ userId: id })
await app.prisma.user.findOne({ where: { id } })

// batched together at the end
app.prisma.onboarding.deleteMany({ where: { userId: id } })
app.prisma.availabilityTemplate.deleteMany({
  where: { appId: availabilityApp.id },
}),
app.prisma.availabilityApp.delete({ where: { id: availabilityApp.id } })
app.prisma.user.delete({ where: { id } })

This is because Prisma queries are then-ables, meaning they only execute when you call await or .then() or .catch(). This is called lazy evaluation. This is different then a regular promise which starts executing immediately. This would be called eager evaluation or immediate evaluation.

This was an understandable source of confusion for @Sytten because most libraries using promises eagerly evaluate. For example:

const fs = require('fs/promises')
fs.readFile("./test.txt") // starts reading the file immediately!

But in the Prisma client:

const deleteOperation = app.prisma.onboarding.deleteMany({ where: { userId: id } }) // doesn't do anything
// ...
deleteOperation.then() // now it executes
// or..
await deleteOperation // now it executes.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:20
  • Comments:9 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
bennettdamscommented, Nov 30, 2022

Maybe I’m misunderstanding the examples in this issue, but how would one do “fire-and-forget” queries?

Example: I have a simple API endpoint where some “post” data is returned. For each request, I also want to increment the view counter of that post. Something like:

async function foo(postId: string) {
  // increment post views
  prisma.post.update({
    where: { id: postId },
    data: { noOfViews: { increment: 1 } },
    select: null,
  });
  
  // find post data
  return await prisma.post.findUnique({
    where: { id: postId },
    select: defaultPostSelect,
  });
}

I don’t care about the result of the update query, so I also don’t want to wait for it at all, as otherwise each request for “post” data will have to wait until the “increment view” operation is finished first.

There’s a similar discussion for this use case, but it’s from 2020, so I’m not sure if it is still relevant.

1reaction
Jolg42commented, Aug 17, 2022

@shadoath Yes that should be faster, though in the transaction queries will be executed sequentially. Another option would be to use Promise.all() or Promise.allSettled() to run all the queries at the same time, like

const queries = [
    prisma.user.findUnique({ where: { id: 1 } }),
    prisma.user.findUnique({ where: { id: 2 } }),
  ]
const users = await Promise.all(queries)
Read more comments on GitHub >

github_iconTop Results From Across the Web

Query optimization - Prisma
This guide describes ways to optimize query performance, debug performance issues, and how to tackle common performance issues such as the ...
Read more >
Raw database access (Reference) - Prisma
Learn how you can send raw SQL and MongoDB queries to your database using the raw() methods from the Prisma Client API.
Read more >
Transactions and batch queries (Reference) - Prisma
Sequential operations: pass an array of Prisma Client queries to be executed sequentially inside a transaction, using $transaction<R>(queries: PrismaPromise<R>[] ...
Read more >
Prisma Client API (Reference)
Logs all queries run by Prisma. For relational databases this logs all SQL queries. Example: prisma:query SELECT "public"."User"."id" ...
Read more >
Prisma Client
Note that queries will only run if used with await or chained with .then() . · The client methods are "thenable", they return...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found