From daefd6f004606ca86d177bab18d18a7d9c3b3853 Mon Sep 17 00:00:00 2001 From: Jan Piotrowski Date: Wed, 8 Feb 2023 20:08:48 +0100 Subject: [PATCH 1/5] fix(null-and-undefined): Describe `find` cases and give `update` a headline TODO --- .../02-prisma-client/080-null-and-undefined.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx b/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx index a6ac332040..38e388eff9 100644 --- a/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx +++ b/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx @@ -14,6 +14,12 @@ Prisma Client differentiates between `null` and `undefined`: > **Note**: This is particularly important to account for in [a **Prisma with GraphQL context**, where `null` and `undefined` are interchangeable](#use-case-null-and-undefined-in-a-graphql-resolver). +## null and undefined in `find*` queries + +TODO Simple example with `findMany` and `findFirst` that shows how a query with `foo: undefined` (e.g. https://github.com/prisma/prisma/issues/17723) returns everything or any first entry as it is filtered out of the query + +## null and undefined in `update*` queries + In the following example, if `emailInput` is `null`, the query sets `email` (a **mandatory** field) to `undefined` - which means ✔ **do not include this in the update**: ```ts From e3c2edfc66e0dfe6922e678a6622e86d8d7d6507 Mon Sep 17 00:00:00 2001 From: Jan Piotrowski Date: Wed, 8 Feb 2023 20:20:36 +0100 Subject: [PATCH 2/5] Update 080-null-and-undefined.mdx --- .../02-prisma-client/080-null-and-undefined.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx b/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx index 38e388eff9..7fabf918ea 100644 --- a/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx +++ b/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx @@ -14,11 +14,11 @@ Prisma Client differentiates between `null` and `undefined`: > **Note**: This is particularly important to account for in [a **Prisma with GraphQL context**, where `null` and `undefined` are interchangeable](#use-case-null-and-undefined-in-a-graphql-resolver). -## null and undefined in `find*` queries +## null and undefined in find* queries TODO Simple example with `findMany` and `findFirst` that shows how a query with `foo: undefined` (e.g. https://github.com/prisma/prisma/issues/17723) returns everything or any first entry as it is filtered out of the query -## null and undefined in `update*` queries +## null and undefined in update* queries In the following example, if `emailInput` is `null`, the query sets `email` (a **mandatory** field) to `undefined` - which means ✔ **do not include this in the update**: From ce1a97afa4f19f0752742f0c56be9307f1d54c0b Mon Sep 17 00:00:00 2001 From: Sabin Adams Date: Wed, 8 Feb 2023 16:11:01 -0800 Subject: [PATCH 3/5] Revises the null and undefined page --- .../080-null-and-undefined.mdx | 214 +++++++++++++----- 1 file changed, 157 insertions(+), 57 deletions(-) diff --git a/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx b/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx index 7fabf918ea..dfd8df34e9 100644 --- a/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx +++ b/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx @@ -12,96 +12,196 @@ Prisma Client differentiates between `null` and `undefined`: - `null` is a **value** - `undefined` means **do nothing** -> **Note**: This is particularly important to account for in [a **Prisma with GraphQL context**, where `null` and `undefined` are interchangeable](#use-case-null-and-undefined-in-a-graphql-resolver). + -## null and undefined in find* queries - -TODO Simple example with `findMany` and `findFirst` that shows how a query with `foo: undefined` (e.g. https://github.com/prisma/prisma/issues/17723) returns everything or any first entry as it is filtered out of the query - -## null and undefined in update* queries +This is particularly important to account for in [a **Prisma with GraphQL context**, where `null` and `undefined` are interchangeable](#use-case-null-and-undefined-in-a-graphql-resolver). -In the following example, if `emailInput` is `null`, the query sets `email` (a **mandatory** field) to `undefined` - which means ✔ **do not include this in the update**: + + +The data below represents a `User` table. This set of data will be used in all of the examples below: + +| id | name | email | +| --- | ------- | ----------------- | +| 1 | Nikolas | nikolas@gmail.com | +| 2 | Martin | martin@gmail.com | +| 3 | _empty_ | sabin@gmail.com | +| 4 | Tyler | tyler@gmail.com | + + + + + +## null and undefined in queries that affect _many_ records + +This section will cover how `undefined` and `null` values in the filters of a query affect these functions: + +- `findMany` +- `updateMany` +- `deleteMany` +- `count` +- `aggregate` +- `groupBy` + +Consider the following Prisma Client query which searches for any user whose `name` column's value matches the provided value: ```ts -const update = await prisma.user.update({ +const users = await prisma.user.findMany({ where: { - id: 1, - }, - data: { - name: "Petunia", -| email: emailInput != null ? emailInput : undefined, // If null, don't include in update! + name: null, }, -}); +}) +``` -function getEmail() { - const random = Math.floor(Math.random() * 10); +Because `null` was provided as the filter criteria for the `name` column, Prisma Client will generate a query that searches for any records in the `User` table whose `name` column is _empty_. - if (random > 5) { - return "ariadne@prisma.io"; // Could be null! - } +The results of the query will be: - return null; -} +```json +[ + { + "id": 3, + "name": null, + "email": "sabin@gmail.com" + } +] ``` -Setting a field value to `undefined` is the same as not including the `email` field in the `update` query **at all**: +Now consider the scenario where you invoke the same query, except `undefined` is used as the filter criteria: ```ts -const update = await prisma.user.update({ +const users = await prisma.user.findMany({ where: { - id: 1, + name: undefined, }, - data: { - name: "Petunia", -| // No email update here... +}) +``` + +When `undefined` is used in this way, you essentially tell Prisma Client you have decided _not to define a filter_ for that column. An equivalent way to write the above query would be: + +```ts +const users = await prisma.user.findMany() +``` + +This query will select every row from the `User` table. + +The resulting dataset from the query using `undefined` as the filter criteria will contain the entire set of users: + +```json +[ + { + "id": 1, + "name": "Nikolas", + "email": "nikolas@gmail.com" }, -}); + { + "id": 2, + "name": "Martin", + "email": "martin@gmail.com" + }, + { + "id": 3, + "name": null, + "email": "sabin@gmail.com" + }, + { + "id": 4, + "name": "Tyler", + "email": "tyler@gmail.com" + } +] +``` + +Although this section's examples focused on the `findMany` function, the same concepts apply to any function that can affect multiple records, such as `updateMany` and `deleteMany`. + +## null and undefined in queries that affect _one_ record + +This section will cover how `undefined` and `null` values in the filter of a query affect these functions: + +- `findFirst` +- `findFirstOrThrow` +- `findUnique` +- `findUniqueOrThrow` +- `delete` +- `update` +- `upsert` -function getEmail() { - const random = Math.floor(Math.random() * 10); + - if (random > 5) { - return "ariadne@prisma.io"; // Could be null! +`null` is not a valid filter value in a `findUnique` query. + + + +The query behavior when using `null` and `undefined` in the filter criteria of a query that affects a single record is very similar to the behaviors described in the previous section. + +Consider the following query: + +```ts +const user = await prisma.user.findFirst({ + where: { + name: null, + }, +}) +``` + +Because `null` was used as the filter on the `name` column, Prisma Client will generate a query that searches for the first record in the `User` table whose `name` value is empty. + +The result of either of the query above will be as follows: + +```json +[ + { + "id": 3, + "name": null, + "email": "sabin@gmail.com" } +] +``` - return null; -} +If `undefined` is instead used as the filter criteria on the `name` column, the query will act as if no filter criteria was passed to that column at all. + +Consider the query below: + +```ts +const user = await prisma.user.findFirst({ + where: { + name: undefined, + }, +}) ``` -By contrast, the following would ✘ **not work** as the mandatory `email` field cannot be `null`: +Another way to represent the above query is: ```ts -email: isValid(emailInput) ? emailInput : null, // email is a mandatory field! +const user = await prisma.user.findFirst() +``` + +In this scenario, the query will return the very first record in the database. The results will be: + +```json +[ + { + "id": 1, + "name": "Nikolas", + "email": "nikolas@gmail.com" + } +] ``` -> **Note**: TypeScript will give you an error in this scenario: `Type 'null' is not assignable to type 'string'. ts(2322)` +Although this section's examples focused on the `findFirst` function, the same concepts apply to any function that affects a single record. + +## null and undefined in a GraphQL resolver -
Expand for sample schema +For this example, consider a database based on the following Prisma schema: ```prisma model User { - email String @unique id Int @id @default(autoincrement()) + email String @unique name String? - posts Post[] -} - -model Post { - id String @id @default(cuid()) - title String - authorId Int? - views Int? - author User? @relation(fields: [authorId], references: [id]) } ``` -
- - - -## Use case: null and undefined in a GraphQL resolver - -In the following example mutation that updates a user, both `authorEmail` and `name` accept `null` - from a GraphQL perspective, this means that fields are **optional**: +In the following GraphQL mutation that updates a user, both `authorEmail` and `name` accept `null`. From a GraphQL perspective, this means that fields are **optional**: ```ts type Mutation { @@ -112,8 +212,8 @@ type Mutation { However, if you pass `null` values for `authorEmail` or `authorName` on to Prisma, the following will happen: -- If `args.authorEmail` is `null`, the query will **fail** - `email` does not accept `null` ✘ -- If `args.authorName` is `null`, Prisma changes the value of `name` to `null` - this is probably not how you want an update to work ✘ +- If `args.authorEmail` is `null`, the query will **fail**. `email` does not accept `null`. +- If `args.authorName` is `null`, Prisma changes the value of `name` to `null`. This is probably not how you want an update to work. ```ts updateUser: (parent, args, ctx: Context) => { From 3caa2c1b77d5c49fcc60dd010eedcb3afa6f4d11 Mon Sep 17 00:00:00 2001 From: Sabin Adams Date: Thu, 9 Feb 2023 09:47:58 -0800 Subject: [PATCH 4/5] Revises page --- .../080-null-and-undefined.mdx | 119 ++++++++++++------ 1 file changed, 79 insertions(+), 40 deletions(-) diff --git a/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx b/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx index dfd8df34e9..832b6444f8 100644 --- a/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx +++ b/content/200-concepts/100-components/02-prisma-client/080-null-and-undefined.mdx @@ -33,16 +33,15 @@ The data below represents a `User` table. This set of data will be used in all o ## null and undefined in queries that affect _many_ records -This section will cover how `undefined` and `null` values in the filters of a query affect these functions: +This section will cover how `undefined` and `null` values affect the behavior of queries that interact with or create multiple records in a database. -- `findMany` -- `updateMany` -- `deleteMany` -- `count` -- `aggregate` -- `groupBy` +### Null -Consider the following Prisma Client query which searches for any user whose `name` column's value matches the provided value: +Consider the following Prisma Client query which searches for all users whose `name` value matches the provided `null` value: + + + + ```ts const users = await prisma.user.findMany({ @@ -52,9 +51,9 @@ const users = await prisma.user.findMany({ }) ``` -Because `null` was provided as the filter criteria for the `name` column, Prisma Client will generate a query that searches for any records in the `User` table whose `name` column is _empty_. + -The results of the query will be: + ```json [ @@ -66,7 +65,19 @@ The results of the query will be: ] ``` -Now consider the scenario where you invoke the same query, except `undefined` is used as the filter criteria: + + + + +Because `null` was provided as the filter for the `name` column, Prisma Client will generate a query that searches for all records in the `User` table whose `name` column is _empty_. + +### Undefined + +Now consider the scenario where you run the same query with `undefined` as the filter value on the `name` column: + + + + ```ts const users = await prisma.user.findMany({ @@ -76,15 +87,8 @@ const users = await prisma.user.findMany({ }) ``` -When `undefined` is used in this way, you essentially tell Prisma Client you have decided _not to define a filter_ for that column. An equivalent way to write the above query would be: - -```ts -const users = await prisma.user.findMany() -``` - -This query will select every row from the `User` table. - -The resulting dataset from the query using `undefined` as the filter criteria will contain the entire set of users: + + ```json [ @@ -111,29 +115,46 @@ The resulting dataset from the query using `undefined` as the filter criteria wi ] ``` + + + +Using `undefined` as a value in a filter essentially tells Prisma Client you have decided _not to define a filter_ for that column. + +An equivalent way to write the above query would be: + +```ts +const users = await prisma.user.findMany() +``` + +This query will select every row from the `User` table. + + + +**Note**: Using `undefined` as the value of any key in a Prisma Client query's parameter object will cause Prisma to act as if that key was not provided at all. + + + Although this section's examples focused on the `findMany` function, the same concepts apply to any function that can affect multiple records, such as `updateMany` and `deleteMany`. ## null and undefined in queries that affect _one_ record -This section will cover how `undefined` and `null` values in the filter of a query affect these functions: - -- `findFirst` -- `findFirstOrThrow` -- `findUnique` -- `findUniqueOrThrow` -- `delete` -- `update` -- `upsert` +This section will cover how `undefined` and `null` values affect the behavior of queries that interact with or create a single record in a database. -`null` is not a valid filter value in a `findUnique` query. +**Note**: `null` is not a valid filter value in a `findUnique` query. The query behavior when using `null` and `undefined` in the filter criteria of a query that affects a single record is very similar to the behaviors described in the previous section. -Consider the following query: +### Null + +Consider the following query where `null` is used to filter the `name` column: + + + + ```ts const user = await prisma.user.findFirst({ @@ -143,9 +164,9 @@ const user = await prisma.user.findFirst({ }) ``` -Because `null` was used as the filter on the `name` column, Prisma Client will generate a query that searches for the first record in the `User` table whose `name` value is empty. + -The result of either of the query above will be as follows: + ```json [ @@ -157,10 +178,21 @@ The result of either of the query above will be as follows: ] ``` -If `undefined` is instead used as the filter criteria on the `name` column, the query will act as if no filter criteria was passed to that column at all. + + + +Because `null` was used as the filter on the `name` column, Prisma Client will generate a query that searches for the first record in the `User` table whose `name` value is _empty_. + +### Undefined + +If `undefined` is used as the filter value on the `name` column instead, _the query will act as if no filter criteria was passed to that column at all_. Consider the query below: + + + + ```ts const user = await prisma.user.findFirst({ where: { @@ -169,13 +201,9 @@ const user = await prisma.user.findFirst({ }) ``` -Another way to represent the above query is: + -```ts -const user = await prisma.user.findFirst() -``` - -In this scenario, the query will return the very first record in the database. The results will be: + ```json [ @@ -187,6 +215,17 @@ In this scenario, the query will return the very first record in the database. T ] ``` + + + +In this scenario, the query will return the very first record in the database. + +Another way to represent the above query is: + +```ts +const user = await prisma.user.findFirst() +``` + Although this section's examples focused on the `findFirst` function, the same concepts apply to any function that affects a single record. ## null and undefined in a GraphQL resolver From 022edfaa1e2ee100dee8f8a3a4ca6b9fd8abde15 Mon Sep 17 00:00:00 2001 From: Jan Piotrowski Date: Wed, 15 Nov 2023 15:29:28 +0100 Subject: [PATCH 5/5] Update cSpell.json --- cSpell.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cSpell.json b/cSpell.json index 13b402dc94..d7ee1414e6 100644 --- a/cSpell.json +++ b/cSpell.json @@ -72,7 +72,8 @@ "Vitess", "libgcc", "libc", - "Distroless" + "Distroless", + "Nikolas", ], "patterns": [ {