diff --git a/cSpell.json b/cSpell.json
index 6787fe9f98..6579087e2f 100644
--- a/cSpell.json
+++ b/cSpell.json
@@ -51,6 +51,7 @@
"Nuxt",
"Sveltekit",
"Pothos",
+ "backoff",
"Replibyte",
"Snaplet"
],
diff --git a/content/200-concepts/100-components/02-prisma-client/053-middleware/200-logging-middleware.mdx b/content/200-concepts/100-components/02-prisma-client/053-middleware/200-logging-middleware.mdx
index 059f0d6eab..145fa01447 100644
--- a/content/200-concepts/100-components/02-prisma-client/053-middleware/200-logging-middleware.mdx
+++ b/content/200-concepts/100-components/02-prisma-client/053-middleware/200-logging-middleware.mdx
@@ -84,3 +84,7 @@ enum Role {
```
+
+## Going further
+
+You can also use [Prisma Client extensions](/concepts/components/prisma-client/client-extensions) to log the time it takes to perform a query. A functional example can be found in [this GitHub repository](https://github.com/prisma/prisma-client-extensions/tree/main/query-logging).
diff --git a/content/200-concepts/100-components/02-prisma-client/061-custom-validation.mdx b/content/200-concepts/100-components/02-prisma-client/061-custom-validation.mdx
index 096249f324..75aedb04ee 100644
--- a/content/200-concepts/100-components/02-prisma-client/061-custom-validation.mdx
+++ b/content/200-concepts/100-components/02-prisma-client/061-custom-validation.mdx
@@ -6,13 +6,149 @@ metaDescription: 'This page explains how to add custom validation to Prisma Clie
-Prisma Client has type-safety and run-time type validation but does not include validation for user input.
+You can add runtime validation for your user input for Prisma Client queries in one of the following ways:
-This means you can use any validation library you'd like. The Node.js ecosystem offers a number of high-quality, easy-to-use validation libraries to choose from including: [joi](https://github.com/sideway/joi), [validator.js](https://github.com/validatorjs/validator.js), [Yup](https://github.com/jquense/yup), [Zod](https://github.com/colinhacks/zod) and [Superstruct](https://github.com/ianstormtaylor/superstruct).
+- [Prisma Client extensions](/concepts/components/prisma-client/client-extensions)
+- A custom function
+
+You can use any validation library you'd like. The Node.js ecosystem offers a number of high-quality, easy-to-use validation libraries to choose from including: [joi](https://github.com/sideway/joi), [validator.js](https://github.com/validatorjs/validator.js), [Yup](https://github.com/jquense/yup), [Zod](https://github.com/colinhacks/zod) and [Superstruct](https://github.com/ianstormtaylor/superstruct).
-## Custom Signup Validation
+## Input validation with Prisma Client extensions
+
+> Prisma Client extensions are currently in [Preview](/about/prisma/releases#preview).
+
+This example adds runtime validation when creating and updating values using a Zod schema to check that the data passed to Prisma Client is valid.
+
+
+
+Query extensions do not currently work for nested operations. In this example, validations are only run on the top level data object passed to methods such as `prisma.product.create()`. Validations implemented this way do not automatically run for [nested writes](https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#nested-writes).
+
+
+
+, ]}>
+
+
+
+```ts copy
+import { PrismaClient, Prisma } from "@prisma/client";
+import { z } from 'zod'
+
+/**
+ * Zod schema
+ */
+export const ProductCreateInput = z.object({
+ slug: z
+ .string()
+ .max(100)
+ .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
+ name: z.string().max(100),
+ description: z.string().max(1000),
+ price: z
+ .instanceof(Prisma.Decimal)
+ .refine((price) => price.gte("0.01") && price.lt("1000000.00")),
+}) satisfies z.Schema;
+
+/**
+ * Prisma Client Extension
+ */
+const prisma = new PrismaClient().$extends({
+ query: {
+ product: {
+ create({ args, query }) {
+ args.data = ProductCreateInput.parse(args.data);
+ return query(args);
+ },
+ update({ args, query }) {
+ args.data = ProductCreateInput.partial().parse(args.data);
+ return query(args);
+ },
+ updateMany({ args, query }) {
+ args.data = ProductCreateInput.partial().parse(args.data);
+ return query(args);
+ },
+ upsert({ args, query }) {
+ args.create = ProductCreateInput.parse(args.create);
+ args.update = ProductCreateInput.partial().parse(args.update);
+ return query(args);
+ },
+ },
+ },
+});
+
+async function main (){
+ /**
+ * Example usage
+ */
+ // Valid product
+ const product = await prisma.product.create({
+ data: {
+ slug: "example-product",
+ name: "Example Product",
+ description: "Lorem ipsum dolor sit amet",
+ price: new Prisma.Decimal("10.95"),
+ },
+ });
+
+ // Invalid product
+ try {
+ await prisma.product.create({
+ data: {
+ slug: "invalid-product",
+ name: "Invalid Product",
+ description: "Lorem ipsum dolor sit amet",
+ price: new Prisma.Decimal("-1.00"),
+ },
+ });
+ } catch (err: any) {
+ console.log(err?.cause?.issues);
+ }
+}
+
+main()
+```
+
+
+
+
+
+```prisma copy
+datasource db {
+ provider = "postgresql"
+ url = env("DATABASE_URL")
+}
+
+generator client {
+ provider = "prisma-client-js"
+ previewFeatures = ["clientExtensions"]
+}
+
+model Product {
+ id String @id @default(cuid())
+ slug String
+ name String
+ description String
+ price Decimal
+ reviews Review[]
+}
+
+model Review {
+ id String @id @default(cuid())
+ body String
+ stars Int
+ product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
+ productId String
+}
+```
+
+
+
+
+
+The above example uses a Zod schema to validate and parse data provided in a query at runtime before a record is written to the database.
+
+## Input validation with a custom validation function
Here's an example using [Superstruct](https://github.com/ianstormtaylor/superstruct) to validate that the data needed to signup a new user is correct:
@@ -50,7 +186,8 @@ async function signup(input: Signup): Promise {
The example above shows how you can create a custom type-safe `signup` function that ensures the input is valid before creating a user.
-## Going Further
+## Going further
+- Learn how you can use [Prisma Client extensions](/concepts/components/prisma-client/client-extensions) to add input validation for your queries — [example](https://github.com/prisma/prisma-client-extensions/tree/main/input-validation).
- Learn how you can organize your code better by moving the `signup` function into [a custom model](/concepts/components/prisma-client/custom-models).
- There's an [outstanding feature request](https://github.com/prisma/prisma/issues/3528) to bake user validation into Prisma Client. If you'd like to see that happen, make sure to upvote that issue and share your use case!
diff --git a/content/200-concepts/100-components/02-prisma-client/062-computed-fields.mdx b/content/200-concepts/100-components/02-prisma-client/062-computed-fields.mdx
index 367f818e78..37746bea17 100644
--- a/content/200-concepts/100-components/02-prisma-client/062-computed-fields.mdx
+++ b/content/200-concepts/100-components/02-prisma-client/062-computed-fields.mdx
@@ -10,9 +10,106 @@ Computed fields allow you to derive a new field based on existing data. A common
-## Deriving a Full Name from a First and Last Name
+## Using a Prisma Client extension
-Prisma Client does not yet natively support computed fields, but with a bit of TypeScript magic, you can define a function that accepts a generic as an input then extend that generic to ensure it conforms to a specific structure. Finally, you can return that generic with additional computed fields. Let's see how that might look:
+> Prisma Client extensions are currently in [Preview](/about/prisma/releases#preview).
+
+The following example illustrates how to create a [Prisma Client extension](/concepts/components/prisma-client/client-extensions) that adds a `fullName` computed field at runtime to the `User` model in a Prisma schema.
+
+ ,]}>
+
+
+
+
+
+
+
+```ts
+import { PrismaClient } from '@prisma/client'
+
+const prisma = new PrismaClient().$extends({
+ result: {
+ user: {
+ fullName: {
+ needs: { firstName: true, lastName: true },
+ compute(user) {
+ return `${user.firstName} ${user.lastName}`
+ },
+ },
+ },
+ },
+})
+
+async function main() {
+ /**
+ * Example query containing the `fullName` computed field in the response
+ */
+ const user = await prisma.user.findFirst()
+}
+
+main()
+```
+
+
+
+
+```js no-copy
+{
+ id: 'clgzkgy2j00004tc6iwu3gkzu',
+ firstName: 'Aurelia',
+ lastName: 'Schneider',
+ email: 'Jalen_Berge40@hotmail.com',
+ fullName: 'Aurelia Schneider',
+}
+```
+
+
+
+
+
+
+
+
+
+```prisma copy
+datasource db {
+ provider = "postgresql"
+ url = env("DATABASE_URL")
+}
+
+generator client {
+ provider = "prisma-client-js"
+ previewFeatures = ["clientExtensions"]
+}
+
+model User {
+ id Int @id @default(autoincrement())
+ email String @unique
+ name String?
+
+ posts Post[]
+}
+
+model Post {
+ id Int @id @default(autoincrement())
+ title String
+ published Boolean @default(true)
+ content String?
+
+ authorId Int?
+ author User? @relation(fields: [authorId], references: [id])
+}
+```
+
+
+
+
+
+The computed fields are type-safe and can return anything from a concatenated value to complex objects or functions that can act as an instance method for your models.
+
+## Using a computation function
+
+Prisma Client does not yet natively support computed fields, but, you can define a function that accepts a generic type as an input then extend that generic to ensure it conforms to a specific structure. Finally, you can return that generic with additional computed fields. Let's see how that might look:
, ]}>
@@ -74,7 +171,8 @@ A `WithFullName` return type has also been defined, which takes whatever `
With this function, any object that contains `firstName` and `lastName` keys can compute a `fullName`. Pretty neat, right?
-## Going Further
+## Going further
+- Learn how you can use [Prisma Client extensions](/concepts/components/prisma-client/client-extensions) to add a computed field to your schema — [example](https://github.com/prisma/prisma-client-extensions/tree/main/computed-fields).
- Learn how you can move the `computeFullName` function into [a custom model](/concepts/components/prisma-client/custom-models).
- There's an [outstanding feature request](https://github.com/prisma/prisma/issues/3394) to add native support to Prisma Client. If you'd like to see that happen, make sure to upvote that issue and share your use case!
diff --git a/content/200-concepts/100-components/02-prisma-client/063-excluding-fields.mdx b/content/200-concepts/100-components/02-prisma-client/063-excluding-fields.mdx
index aed449f449..2851b919b8 100644
--- a/content/200-concepts/100-components/02-prisma-client/063-excluding-fields.mdx
+++ b/content/200-concepts/100-components/02-prisma-client/063-excluding-fields.mdx
@@ -65,7 +65,7 @@ In the TypeScript example, we've provided two generics: `User` and `Key`. The `K
These generics flow through the logic, returning a `User` that omits the list of `Key`s provided.
-## Going Further
+## Going further
- Learn how you can move the `exclude` function into [a custom model](/concepts/components/prisma-client/custom-models).
- There's an [outstanding feature request](https://github.com/prisma/prisma/issues/5042) to add exclude support natively in Prisma Client. If you'd like to see that happen, make sure to upvote that issue and share your use case!
diff --git a/content/200-concepts/100-components/02-prisma-client/064-custom-models.mdx b/content/200-concepts/100-components/02-prisma-client/064-custom-models.mdx
index 898729f930..0fd28a3b41 100644
--- a/content/200-concepts/100-components/02-prisma-client/064-custom-models.mdx
+++ b/content/200-concepts/100-components/02-prisma-client/064-custom-models.mdx
@@ -6,11 +6,95 @@ metaDescription: 'This page explains how to wrap Prisma Client in custom models'
-As your application grows, you may find the need to group related logic together. We suggest either wrapping a model in a class or extending Prisma Client model object.
+As your application grows, you may find the need to group related logic together. We suggest either:
+
+- Creating static methods using a [Prisma Client extension](/concepts/components/prisma-client/client-extensions)
+- Wrapping a model in a class
+- Extending Prisma Client model object
-## Wrap a Prisma Model in a Class
+## Static methods with Prisma Client extensions
+
+> Prisma Client extensions are currently in [Preview](/about/prisma/releases#preview).
+
+The following example demonstrates how to create a Prisma Client extension that adds a `signUp` and `findManyByDomain` methods to a User model.
+
+,]}>
+
+
+
+```tsx
+import bcrypt from 'bcryptjs'
+import { PrismaClient } from '@prisma/client'
+
+const prisma = new PrismaClient().$extends({
+ model: {
+ user: {
+ async signUp(email: string, password: string) {
+ const hash = await bcrypt.hash(password, 10)
+ return prisma.user.create({
+ data: {
+ email,
+ password: {
+ create: {
+ hash,
+ },
+ },
+ },
+ })
+ },
+
+ async findManyByDomain(domain: string) {
+ return prisma.user.findMany({
+ where: { email: { endsWith: `@${domain}` } },
+ })
+ },
+ },
+ },
+})
+
+async function main() {
+ // Example usage
+ await prisma.user.signUp('user2@example2.com', 's3cret')
+
+ await prisma.user.findManyByDomain('example2.com')
+}
+```
+
+
+
+
+
+```prisma file="prisma/schema.prisma" copy
+datasource db {
+ provider = "postgresql"
+ url = env("DATABASE_URL")
+}
+
+generator client {
+ provider = "prisma-client-js"
+ previewFeatures = ["clientExtensions"]
+}
+
+model User {
+ id String @id @default(cuid())
+ email String
+ password Password?
+}
+
+model Password {
+ hash String
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+ userId String @unique
+}
+```
+
+
+
+
+
+## Wrap a model in a class
In the example below, you'll see how you can wrap the `user` model in the Prisma Client within a `Users` class.
@@ -50,7 +134,7 @@ Note that in the example above, you're only exposing a `signup` method from Pris
This approach works well when you have a large application and you want to intentionally limit what your models can do.
-## Extending Prisma Client
+## Extending Prisma Client model object
But what if you don't want to hide existing functionality but still want to group custom functions together? In this case, you can use `Object.assign` to extend Prisma Client without limiting its functionality:
@@ -89,3 +173,7 @@ async function main() {
```
Now you can use your custom `signup` method alongside `count`, `updateMany`, `groupBy` and all of the other wonderful methods that Prisma Client provides. Best of all, it's all type-safe!
+
+## Going further
+
+We recommend using [Prisma Client extensions](/concepts/components/prisma-client/client-extensions) to extend your models with [custom model methods](https://github.com/prisma/prisma-client-extensions/tree/main/instance-methods).
diff --git a/content/200-concepts/100-components/02-prisma-client/260-client-extensions/200-extension-examples.mdx b/content/200-concepts/100-components/02-prisma-client/260-client-extensions/200-extension-examples.mdx
new file mode 100644
index 0000000000..c57df5d3c7
--- /dev/null
+++ b/content/200-concepts/100-components/02-prisma-client/260-client-extensions/200-extension-examples.mdx
@@ -0,0 +1,37 @@
+---
+title: 'Examples'
+metaTitle: 'Prisma Client Extension | Examples'
+metaDescription: 'Extend the functionality of Prisma Client: Examples'
+---
+
+
+
+Prisma Client extensions is currently in [Preview](/about/prisma/releases#preview). The extensions are provided as examples only, and without warranty. They are not
+intended to be used in production environments.
+
+
+
+## Examples
+
+| Example | Description |
+| :---------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------ |
+| [`audit-log-context`](https://github.com/prisma/prisma-client-extensions/tree/main/audit-log-context) | Provides the current user's ID as context to Postgres audit log triggers |
+| [`callback-free-itx`](https://github.com/prisma/prisma-client-extensions/tree/main/callback-free-itx) | Adds a method to start interactive transactions without callbacks |
+| [`computed-fields`](https://github.com/prisma/prisma-client-extensions/tree/main/computed-fields) | Adds virtual / computed fields to result objects |
+| [`input-transformation`](https://github.com/prisma/prisma-client-extensions/tree/main/input-transformation) | Transforms the input arguments passed to Prisma Client queries to filter the result set |
+| [`input-validation`](https://github.com/prisma/prisma-client-extensions/tree/main/input-validation) | Runs custom validation logic on input arguments passed to mutation methods |
+| [`instance-methods`](https://github.com/prisma/prisma-client-extensions/tree/main/instance-methods) | Adds Active Record-like methods like `save()` and `delete()` to result objects |
+| [`json-field-types`](https://github.com/prisma/prisma-client-extensions/tree/main/json-field-types) | Uses strongly-typed runtime parsing for data stored in JSON columns |
+| [`model-filters`](https://github.com/prisma/prisma-client-extensions/tree/main/model-filters) | Adds reusable filters that can composed into complex `where` conditions for a model |
+| [`obfuscated-fields`](https://github.com/prisma/prisma-client-extensions/tree/main/obfuscated-fields) | Prevents sensitive data (e.g. `password` fields) from being included in results |
+| [`query-logging`](https://github.com/prisma/prisma-client-extensions/tree/main/query-logging) | Wraps Prisma Client queries with simple query timing and logging |
+| [`readonly-client`](https://github.com/prisma/prisma-client-extensions/tree/main/readonly-client) | Creates a client that only allows read operations |
+| [`retry-transactions`](https://github.com/prisma/prisma-client-extensions/tree/main/retry-transactions) | Adds a retry mechanism to transactions with exponential backoff and jitter |
+| [`row-level-security`](https://github.com/prisma/prisma-client-extensions/tree/main/row-level-security) | Uses Postgres row-level security policies to isolate data a multi-tenant application |
+| [`static-methods`](https://github.com/prisma/prisma-client-extensions/tree/main/static-methods) | Adds custom query methods to Prisma Client models |
+| [`transformed-fields`](https://github.com/prisma/prisma-client-extensions/tree/main/transformed-fields) | Demonstrates how to use result extensions to transform query results and add i18n to an app |
+| [`exists-method`](https://github.com/prisma/prisma-client-extensions/tree/main/exists-method) | Demonstrates how to add an `exists` method to all your models |
+
+## Going further
+
+- Learn more about [Prisma Client extensions](/concepts/components/prisma-client/client-extensions).