Skip to main content

Type utilities

Several type utilities exist within Prisma Client that can assist in the creation of highly type-safe extensions.

Type Utilities

Prisma Client type utilities are utilities available within your application and Prisma Client extensions and provide useful ways of constructing safe and extendable types for your extension.

The type utilities available are:

  • Exact<Input, Shape>: Enforces strict type safety on Input. Exact makes sure that a generic type Input strictly complies with the type that you specify in Shape. It narrows Input down to the most precise types.
  • Args<Type, Operation>: Retrieves the input arguments for any given model and operation. This is particularly useful for extension authors who want to do the following:
    • Re-use existing types to extend or modify them.
    • Benefit from the same auto-completion experience as on existing operations.
  • Result<Type, Arguments, Operation>: Takes the input arguments and provides the result for a given model and operation. You would usually use this in conjunction with Args. As with Args, Result helps you to re-use existing types to extend or modify them.
  • Payload<Type, Operation>: Retrieves the entire structure of the result, as scalars and relations objects for a given model and operation. For example, you can use this to determine which keys are scalars or objects at a type level.

The following example creates a new operation, exists, based on findFirst. It has all of the arguments that findFirst.

const prisma = new PrismaClient().$extends({
model: {
$allModels: {
// Define a new `exists` operation on all models
// T is a generic type that corresponds to the current model
async exists<T>(
// `this` refers to the current type, e.g. `prisma.user` at runtime
this: T,

// The `exists` function will use the `where` arguments from the current model, `T`, and the `findFirst` operation
where: Prisma.Args<T, 'findFirst'>['where']
): Promise<boolean> {
// Retrieve the current model at runtime
const context = Prisma.getExtensionContext(this)

// Prisma Client query that retrieves data based
const result = await (context as any).findFirst({ where })
return result !== null
},
},
},
})

async function main() {
const user = await prisma.user.exists({ name: 'Alice' })
const post = await prisma.post.exists({
OR: [
{ title: { contains: 'Prisma' } },
{ content: { contains: 'Prisma' } },
],
})
}

Add a custom property to a method

The following example illustrates how you can add custom arguments, to a method in an extension:

type CacheStrategy = {
swr: number
ttl: number
}

const prisma = new PrismaClient().$extends({
model: {
$allModels: {
findMany<T, A>(
this: T,
args: Prisma.Exact<
A,
// For the `findMany` method, use the arguments from model `T` and the `findMany` method
// and intersect it with `CacheStrategy` as part of `findMany` arguments
Prisma.Args<T, 'findMany'> & CacheStrategy
>
): Prisma.Result<T, A, 'findMany'> {
// method implementation with the cache strategy
},
},
},
})

async function main() {
await prisma.post.findMany({
cacheStrategy: {
ttl: 360,
swr: 60,
},
})
}

The example here is only conceptual. For the actual caching to work, you will have to implement the logic. If you're interested in a caching extension/ service, we recommend taking a look at Prisma Accelerate.