Closed22

prisma client extentionのdocsを読む

hajimismhajimism

When you use a Prisma Client extension, you create an extended client. An extended client is a lightweight variant of the standard Prisma Client that is wrapped by one or more extensions.

lightweightらしい

hajimismhajimism

Add a user.current() method for the User model to get the currently logged-in user.

利用例わかりやすい

hajimismhajimism

この書き方が良さそう

import { Prisma } from '@prisma/client'

// Define the extension
const myExtension = Prisma.defineExtension({
  name: 'signUp', // Optional: name appears in error logs
  model: {        // This is a `model` component
    user: { ... } // The extension logic for the `user` model goes inside the curly braces
  },
})

// Pass the extension to a Prisma Client instance
const xprisma = prisma.$extends(myExtension)
hajimismhajimism

連鎖ができるので

// First of all, store your original Prisma Client in a variable as usual
const prisma = new PrismaClient()

// Declare an extended client that has an extensionA and extensionB
const prismaAB = prisma.$extends(extensionA).$extends(extensionB)
hajimismhajimism

singleton作って中で連鎖させるのが良さそう

function getExtendedClient() {
  return new PrismaClient().$extends({
    /* extension */
  })
}

type ExtendedPrismaClient = ReturnType<typeof getExtendedClient>
hajimismhajimism

When you combine two or more extensions into a single extended client, then the last extension that you declare takes precedence in any conflict. In the example in option 1 above, suppose there is a method called myExtensionMethod() defined in extensionA and a method called myExtensionMethod() in extensionB. When you call prismaAB.myExtensionMethod(), then Prisma Client uses myExtensionMethod() as defined in extensionB.

競合したら後ろの方で上書きされるらしい

hajimismhajimism
hajimismhajimism

用途。今の時点では区別のイメージそんな付いてない。

Possible uses for the model component include the following:

  • New operations to operate alongside existing Prisma Client operations, such as findMany
  • Encapsulated business logic
  • Repetitive operations
  • Model-specific utilities
hajimismhajimism

あーこういうことか、なるほど

const prisma = new PrismaClient().$extends({
  model: {
    user: {
      async signUp(email: string) {
        await prisma.user.create({ data: { email } })
      },
    },
  },
})
hajimismhajimism

これもたしかに

const prisma = new PrismaClient().$extends({
  model: {
    $allModels: {
      async exists<T>(
        this: T,
        where: Prisma.Args<T, 'findFirst'>['where']
      ): Promise<boolean> {
        // Get the current model at runtime
        const context = Prisma.getExtensionContext(this)

        const result = await (context as any).findFirst({ where })
        return result !== null
      },
    },
  },
})
hajimismhajimism
hajimismhajimism

ほーん?metricsなんてついてたんだ

const prisma = new PrismaClient().$extends({
  client: {
    $log: (s: string) => console.log(s),
    async $totalQueries() {
      const index_prisma_client_queries_total = 0
      // Prisma.getExtensionContext(this) in the following block
      // returns the current client instance
      const metricsCounters = await (
        await Prisma.getExtensionContext(this).$metrics.json()
      ).counters

      return metricsCounters[index_prisma_client_queries_total].value
    },
  },
})

async function main() {
  prisma.$log('Hello world')
  const totalQueries = await prisma.$totalQueries()
  console.log(totalQueries)
}
hajimismhajimism
hajimismhajimism

新しいfield生やすやつね

const prisma = new PrismaClient().$extends({
  result: {
    user: {
      fullName: {
        // the dependencies
        needs: { firstName: true, lastName: true },
        compute(user) {
          // the computation logic
          return `${user.firstName} ${user.lastName}`
        },
      },
    },
  },
})

const user = await prisma.user.findFirst()

// return the user's full name, such as "John Doe"
console.log(user.fullName)
hajimismhajimism

Considerations for fields

  • For performance reasons, Prisma Client computes results on access, not on retrieval.
  • You can only create computed fields that are based on scalar fields.
  • You can only use computed fields with select and you cannot aggregate them. For example:

アクセス時算出は覚えておいたほうがいいかも

hajimismhajimism

modelとの使い分けどうなってんだろ

const prisma = new PrismaClient().$extends({
  result: {
    user: {
      save: {
        needs: { id: true },
        compute(user) {
          return () =>
            prisma.user.update({ where: { id: user.id }, data: user })
        },
      },
    },
  },
})

const user = await prisma.user.findUniqueOrThrow({ where: { id: someId } })
user.email = 'mynewmail@mailservice.com'
await user.save()
hajimismhajimism
hajimismhajimism

なるほど、そんなメタ拡張が

const prisma = new PrismaClient().$extends({
  query: {
    async $allOperations({ operation, model, args, query }) {
      const start = performance.now()
      const result = await query(args)
      const end = performance.now()
      const time = end - start
      console.log(
        util.inspect(
          { model, operation, args, time },
          { showHidden: false, depth: null, colors: true }
        )
      )
      return result
    },
  },
})
hajimismhajimism

We include the above example to show that this is possible. However, for performance reasons we recommend that you use the result component type to override existing fields. The result component type usually gives better performance in this situation because it computes only on access. The query component type computes after query execution.

fieldの上書きはresultを拡張しといてアクセス後計算にしとくほうがパフォーマンスの観点から好ましい。

このスクラップは5ヶ月前にクローズされました