2

The new Prisma client extensions provide a way to compute a custom field in the response.

e.g.

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient().$extends({
  result: {
    user: {
      // Add a computed field called `nameAndAge` to the user
      nameAndAge: {
        needs: {
          name: true,
          age: true,
        },
        compute(user) {
          return `${user.name} (${user.age}y)` + getdata();
        },
      },
    },
  },
});

const user = await prisma.user.findFirst();
console.log(user?.nameAndAge);

However, I want to call an async function from within the client like this:

async function getdata(){
  return "external data here!"
}

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient().$extends({
  result: {
    user: {
      // Add a computed field called `nameAndAge` to the user
      nameAndAge: {
        needs: {
          name: true,
          age: true,
        },
        compute(user) {
          return `${user.name} (${user.age}y)` + getdata();
        },
      },
    },
  },
});

const user = await prisma.user.findFirst();
console.log(user?.nameAndAge);

However, this always returns a promise and I can't await the getdata() function in the return.

e.g.

Sonia Lomo (25y)[object Promise]

Is there a solution to this somehow ?

I also tried making the compute function asynchronous then awaiting the getdata() function. e.g.:

async compute(user) {
          return `${user.name} (${user.age}y)` + await getdata();
        },

However, the promise always returns as pending.

Promise { <pending> }

1 Answer 1

1

According to this prisma contributor in this issue

This is works as intended. Purpose of result extensions is to add synchronously computed field to the model with minimum overhead, so it can be queried implicitly

Also the official doc specifies

For performance reasons, Prisma Client computes results on access, not on retrieval.

I've struggles too with this limitation of prisma and my solution was to simply return an async function as the result of the compute method. Then the value can be computed when needed.

const prisma = new PrismaClient().$extends({
  result: {
    user: {
      getNameAndAge: {
        needs: { name: true, age: true },
        compute(user) {
          return async () => (`${user.name} (${user.age}y) ${await getdata()}`)
        },
      },
    },
  },
})

// ...when needed

const joeNameAndAge = await users[0].getNameAndAge()

On the other hand you can define a custom specific for that model that queries and manipulate the data as you need.

You can find more here.

export type UserFindManyWithData = {
  where: Prisma.UserWhereInput
  select: Prisma.UserSelect
}

const prisma = new PrismaClient().$extends({
  model: {
    user: {
      async findManyWithData({ where, select }: UserFindManyWithData) {
        const users = await prisma.user.findMany({ where, select })
                
        // This is not the best strategy for performance, ideally you would like to await all promises at once, but it depends on your project
        for (const user of users) {
          user.nameAndAge = `${user.name} (${user.age}y) ${await getdata()}`
        }
        
        return users
      },
    },
  },
})
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.