From e17b6f0baff17c240334f0accf0c4b24796f9f84 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Fri, 20 Mar 2020 15:28:58 +0100 Subject: [PATCH 01/33] add first pages of real content --- content/01-getting-started/02-quickstart.mdx | 4 +- .../01-add-to-an-existing-project.mdx | 26 +- .../02-start-from-scratch-sql-migrations.mdx | 318 ++++++++++++++++++ .../03-start-from-scratch-prisma-migrate.mdx | 111 ++++++ content/01-getting-started/04-tutorial.mdx | 225 ------------- .../02-understand-prisma/01-introduction.mdx | 7 + content/02-understand-prisma/02-features.mdx | 121 +++++++ content/02-understand-prisma/index.mdx | 6 + .../01-what-is-the-prisma-schema.mdx | 0 .../01-schema/02-data-model.mdx | 0 .../01-schema/03-connectors.mdx | 0 .../01-schema/04-generators.mdx | 0 .../01-schema/05-environment-variables.mdx | 0 .../01-schema/index.mdx | 0 .../02-introspection.mdx | 0 .../01-tools-and-interfaces/index.mdx | 0 .../02-more/01-roadmap.mdx | 0 .../02-more/index.mdx | 0 .../{02-reference => 03-reference}/index.mdx | 0 yarn.lock | 121 +------ 20 files changed, 597 insertions(+), 342 deletions(-) delete mode 100644 content/01-getting-started/04-tutorial.mdx create mode 100644 content/02-understand-prisma/01-introduction.mdx create mode 100644 content/02-understand-prisma/02-features.mdx create mode 100644 content/02-understand-prisma/index.mdx rename content/{02-reference => 03-reference}/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx (100%) rename content/{02-reference => 03-reference}/01-tools-and-interfaces/01-schema/02-data-model.mdx (100%) rename content/{02-reference => 03-reference}/01-tools-and-interfaces/01-schema/03-connectors.mdx (100%) rename content/{02-reference => 03-reference}/01-tools-and-interfaces/01-schema/04-generators.mdx (100%) rename content/{02-reference => 03-reference}/01-tools-and-interfaces/01-schema/05-environment-variables.mdx (100%) rename content/{02-reference => 03-reference}/01-tools-and-interfaces/01-schema/index.mdx (100%) rename content/{02-reference => 03-reference}/01-tools-and-interfaces/02-introspection.mdx (100%) rename content/{02-reference => 03-reference}/01-tools-and-interfaces/index.mdx (100%) rename content/{02-reference => 03-reference}/02-more/01-roadmap.mdx (100%) rename content/{02-reference => 03-reference}/02-more/index.mdx (100%) rename content/{02-reference => 03-reference}/index.mdx (100%) diff --git a/content/01-getting-started/02-quickstart.mdx b/content/01-getting-started/02-quickstart.mdx index be6b3c8283..43abf74903 100644 --- a/content/01-getting-started/02-quickstart.mdx +++ b/content/01-getting-started/02-quickstart.mdx @@ -3,4 +3,6 @@ metaTitle: "" metaDescription: "" duration: "5 min" ---- \ No newline at end of file +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx index fae6e35c04..8730448c16 100644 --- a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx +++ b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx @@ -2,4 +2,28 @@ title: "Add Prisma to an existing project" metaTitle: "" metaDescription: "" ---- \ No newline at end of file +--- + +## Overview +**Note: The content of this page is temporary and will be updated soon.** + +This page explains how to get started with Prisma in an existing project. + +If you don't have a database to try Prisma or just want to explore everything from scratch, check out the ready-to-run [example projects](https://github.com/prisma/prisma-examples/) with use cases for REST, GraphQL, gRPC and more. + +## Add Prisma to an existing project + +Follow these steps to use Prisma in an existing application with a database. Note that these steps assume that you have an existing Node.js or TypeScript project (in case you don't, follow the [extended guide](#extended-guide) below): + +1. Install `prisma2` as a development dependency: `npm install prisma2 --save-dev` +1. Run `npx prisma2 init` to create an empty [Prisma schema]() +1. Set the `url` of the `datasource` block in the Prisma schema to your database connection URL +1. Run `prisma2 introspect` to obtain your data model from the database schema +1. Run `npm install @prisma/client` to add the Prisma Client npm package to your project +1. Run `prisma2 generate` to generate Prisma Client +1. Import Prisma Client into your code: `import { PrismaClient } from '@prisma/client'` +1. Instantiate Prisma Client: `const prisma = new PrismaClient()` +1. Use Prisma Client in code (use your editor's auto-completion to explore its API) + +> **Note**: If Prisma's introspection failed for your database schema, please [open an issue](https://github.com/prisma/prisma2/issues/new) and tell us what went wrong. If you want to help us make Prisma more resilient, please [share your database SQL schema with us](https://github.com/prisma/prisma2/issues/757) so we can add it to our introspection testing suite. + diff --git a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx index 393f65b45d..436f31b403 100644 --- a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx +++ b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx @@ -3,3 +3,321 @@ metaTitle: "" metaDescription: "" --- + +**Note: The content of this page is temporary and will be updated soon.** + +## PostgreSQL + +Follow these steps for an initial Prisma setup: + +1. Run `mkdir hello-prisma` to create your project directory +1. Run `cd hello-prisma` to navigate into it +1. Run `touch schema.prisma` to create an empty [Prisma schema](../../prisma-schema-file.md) +1. Add a `datasource` to the Prisma schema and set your database connection string as the `url`, e.g.: + ```prisma + datasource db { + provider = "postgresql" + url = "postgresql://janedoe:janedoe@localhost:5432/hello-prisma" + } + ``` +1. Run `touch schema.sql` to create your SQL schema and add the following contents to it: + ```sql + CREATE TABLE "public"."User" ( + user_id SERIAL PRIMARY KEY NOT NULL, + name VARCHAR(255), + email VARCHAR(255) UNIQUE NOT NULL + ); + + CREATE TABLE "public"."Post" ( + post_id SERIAL PRIMARY KEY NOT NULL, + title VARCHAR(255) NOT NULL, + content TEXT, + author_id INTEGER, + FOREIGN KEY (author_id) REFERENCES "public"."User"(user_id) + ); + + CREATE TABLE "public"."Profile" ( + profile_id SERIAL PRIMARY KEY NOT NULL, + bio TEXT, + user_id INTEGER NOT NULL, + FOREIGN KEY (user_id) REFERENCES "public"."User"(user_id) + ); + ``` +1. Run the following command to migrate your database schema: + ``` + psql -h __HOST__ -d __DATABASE__ -U __USER__ -f schema.sql + ``` + Note that you need to replace the uppercase placeholders with your database credentials, e.g.: + ``` + psql -h localhost -d hello-prisma -U janedoe -f schema.sql + ``` +1. Add a `generator` to the Prisma schema to be able to generate Prisma Client: + ```prisma + generator client { + provider = "prisma-client-js" + } + ``` +1. Configure project (TypeScript): + ``` + npm init -y + npm install typescript ts-node prisma2 --save-dev + npm install @prisma/client + ``` +1. Run `npx prisma2 introspect` to introspect your database and add your models to the Prisma schema +1. Run `npx prisma2 generate` to generate Prisma Client +1. Run `touch tsconfig.json` and the following contents to it: + ```json + { + "compilerOptions": { + "sourceMap": true, + "outDir": "dist", + "strict": true, + "lib": ["esnext", "dom"], + "esModuleInterop": true + } + } + ``` +1. Run `touch index.ts` to create a source file and add the following code: + ```ts + import { PrismaClient } from '@prisma/client' + + const prisma = new PrismaClient() + + // A `main` function so that we can use async/await + async function main() { + const user1 = await prisma.user.create({ + data: { + email: 'alice@prisma.io', + name: 'Alice', + post: { + create: { + title: 'Watch the talks from Prisma Day 2019', + content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', + }, + }, + }, + include: { + post: true, + }, + }) + console.log(user1) + } + + main() + .catch(e => console.error(e)) + .finally(async () => { + await prisma.disconnect() + }) + ``` +1. Run `npx ts-node index.ts` to execute the script + +## MySQL + +Follow these steps for an initial Prisma setup: + +1. Run `mkdir hello-prisma` to create your project directory +1. Run `cd hello-prisma` to navigate into it +1. Run `touch schema.prisma` to create an empty [Prisma schema](../../prisma-schema-file.md) +1. Add a `datasource` to the Prisma schema and set your database connection string as the `url`, e.g.: + ```prisma + datasource db { + provider = "mysql" + url = "mysql://root:admin@localhost:3306/hello-prisma" + } + ``` +1. Run `touch schema.sql` to create your SQL schema and add the following contents to it: + ```sql + CREATE TABLE User ( + user_id BIGINT NOT NULL AUTO_INCREMENT, + name VARCHAR(255), + email VARCHAR(255) UNIQUE NOT NULL, + PRIMARY KEY (user_id) + ); + + CREATE TABLE Post ( + post_id BIGINT NOT NULL AUTO_INCREMENT, + title VARCHAR(255) NOT NULL, + content TEXT, + author_id BIGINT, + PRIMARY KEY (post_id), + FOREIGN KEY (author_id) REFERENCES User(user_id) + ); + + CREATE TABLE Profile ( + profile_id BIGINT NOT NULL AUTO_INCREMENT, + bio TEXT, + user_id BIGINT NOT NULL, + PRIMARY KEY (profile_id), + FOREIGN KEY (user_id) REFERENCES User(user_id) + ); + ``` +1. Run the following command to migrate your database schema: + ``` + mysql -u __USER__ -p __DATABASE__ < schema.sql + ``` + Note that you need to replace the uppercase placeholders with your database credentials, e.g.: + ``` + mysql -u root -p hello-prisma < schema.sql + ``` +1. Add a `generator` to the Prisma schema to be able to generate Prisma Client: + ```prisma + generator client { + provider = "prisma-client-js" + } + ``` +1. Configure project (TypeScript): + ``` + npm init -y + npm install typescript ts-node prisma2 --save-dev + npm install @prisma/client + ``` +1. Run `npx prisma2 introspect` to introspect your database and add your models to the Prisma schema +1. Run `npx prisma2 generate` to generate Prisma Client +1. Run `touch tsconfig.json` and the following contents to it: + ```json + { + "compilerOptions": { + "sourceMap": true, + "outDir": "dist", + "strict": true, + "lib": ["esnext", "dom"], + "esModuleInterop": true + } + } + ``` +1. Run `touch index.ts` to create a source file and add the following code: + ```ts + import { PrismaClient } from '@prisma/client' + + const prisma = new PrismaClient() + + // A `main` function so that we can use async/await + async function main() { + const user1 = await prisma.user.create({ + data: { + email: 'alice@prisma.io', + name: 'Alice', + post: { + create: { + title: 'Watch the talks from Prisma Day 2019', + content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', + }, + }, + }, + include: { + post: true, + }, + }) + console.log(user1) + } + + main() + .catch(e => console.error(e)) + .finally(async () => { + await prisma.disconnect() + }) + ``` +1. Run `npx ts-node index.ts` to execute the script + + +## SQLite + +Follow these steps for an initial Prisma setup: + +1. Run `mkdir hello-prisma` to create your project directory +1. Run `cd hello-prisma` to navigate into it +1. Run `touch schema.prisma` to create an empty [Prisma schema](../../prisma-schema-file.md) +1. Add a `datasource` to the Prisma schema and set your database connection string as the `url`, e.g.: + ```prisma + datasource db { + provider = "sqlite" + url = "file:./hello-prisma.db" + } + ``` +1. Run `touch schema.sql` to create your SQL schema and add the following contents to it: + ```sql + CREATE TABLE User ( + user_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name VARCHAR(255), + email VARCHAR(255) UNIQUE NOT NULL + ); + + CREATE TABLE Post ( + post_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + title VARCHAR(255) NOT NULL, + content TEXT, + author_id INTEGER, + FOREIGN KEY (author_id) REFERENCES User(user_id) + ); + + CREATE TABLE Profile ( + profile_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + bio TEXT, + user_id INTEGER NOT NULL, + FOREIGN KEY (user_id) REFERENCES User(user_id) + ); + ``` +1. Run the following command to create your SQLite database file from `schema.sql`: + ``` + sqlite3 hello-prisma.db < schema.sql + ``` +1. Add a `generator` to the Prisma schema to be able to generate Prisma Client: + ```prisma + generator client { + provider = "prisma-client-js" + } + ``` +1. Configure project (TypeScript): + ``` + npm init -y + npm install typescript ts-node prisma2 --save-dev + npm install @prisma/client + ``` +1. Run `npx prisma2 introspect` to introspect your database and add your models to the Prisma schema +1. Run `npx prisma2 generate` to generate Prisma Client +1. Run `touch tsconfig.json` and the following contents to it: + ```json + { + "compilerOptions": { + "sourceMap": true, + "outDir": "dist", + "strict": true, + "lib": ["esnext", "dom"], + "esModuleInterop": true + } + } + ``` +1. Run `touch index.ts` to create a source file and add the following code: + ```ts + import { PrismaClient } from '@prisma/client' + + const prisma = new PrismaClient() + + // A `main` function so that we can use async/await + async function main() { + const user1 = await prisma.user.create({ + data: { + email: 'alice@prisma.io', + name: 'Alice', + post: { + create: { + title: 'Watch the talks from Prisma Day 2019', + content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', + }, + }, + }, + include: { + post: true, + }, + }) + console.log(user1) + } + + main() + .catch(e => console.error(e)) + .finally(async () => { + await prisma.disconnect() + }) + ``` +1. Run `npx ts-node index.ts` to execute the script + diff --git a/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx b/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx index 8e92f25404..3184f33272 100644 --- a/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx +++ b/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx @@ -3,3 +3,114 @@ metaTitle: "" metaDescription: "" --- + + +## Overview + +**Note: The content of this page is temporary and will be updated soon.** + +This page explains how to get started with Prisma from scratch by connecting it to an empty database. It uses Prisma Migrate to define and migrate your database schema. + +> **Warning**: Prisma Migrate is currently in an **experimental** state. When using any of the commands below, you need to explicitly opt-in via an `--experimental` flag, e.g. `prisma2 migrate save --name 'init' --experimental`. + +Follow these steps for an initial Prisma setup: + +1. Run `mkdir hello-prisma` to create your project directory +1. Run `cd hello-prisma` to navigate into it +1. Run `touch schema.prisma` to create an empty [Prisma schema](../../prisma-schema-file.md) +1. Add a `datasource` to the Prisma schema and set your database connection string as the `url`, e.g.: + ```prisma + datasource db { + provider = "postgresql" + url = "postgresql://janedoe:janedoe@localhost:5432/hello-prisma" + } + ``` +1. Add your models to the Prisma schema, e.g.: + ```prisma + model Post { + post_id Int @id @default(autoincrement()) + content String? + title String + author User? + } + + model Profile { + profile_id Int @id @default(autoincrement()) + bio String? + user User + } + + model User { + user_id Int @id @default(autoincrement()) + email String @unique + name String? + posts Post[] + profiles Profile[] + } + ``` +1. Add a `generator` to the Prisma schema to be able to generate Prisma Client: + ```prisma + generator client { + provider = "prisma-client-js" + } + ``` +1. Run the following commands to configure your project (TypeScript): + ``` + npm init -y + npm install typescript ts-node prisma2 @types/node --save-dev + npm install @prisma/client + ``` +1. Run `touch tsconfig.json` and the following contents to it: + ```json + { + "compilerOptions": { + "sourceMap": true, + "outDir": "dist", + "strict": true, + "lib": ["esnext"], + "esModuleInterop": true + } + } + ``` +1. Migrate your database by running the following commands: + ``` + npx prisma2 migrate save --name 'init' --experimental + npx prisma2 migrate up --experimental + ``` +1. Generate Prisma Client based on your data model with the following command: + ``` + npx prisma2 generate + ``` +1. Run `touch index.ts` to create a source file and add the following code: + ```ts + import { PrismaClient } from '@prisma/client' + + const prisma = new PrismaClient() + + // A `main` function so that we can use async/await + async function main() { + const user1 = await prisma.user.create({ + data: { + email: 'alice@prisma.io', + name: 'Alice', + posts: { + create: { + title: 'Watch the talks from Prisma Day 2019', + content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', + }, + }, + }, + include: { + posts: true, + }, + }) + console.log(user1) + } + + main() + .catch(e => console.error(e)) + .finally(async () => { + await prisma.disconnect() + }) + ``` +1. Run `npx ts-node index.ts` to execute the script diff --git a/content/01-getting-started/04-tutorial.mdx b/content/01-getting-started/04-tutorial.mdx deleted file mode 100644 index 2190383e9c..0000000000 --- a/content/01-getting-started/04-tutorial.mdx +++ /dev/null @@ -1,225 +0,0 @@ ---- - title: "Tutorial" - metaTitle: "" - metaDescription: "" - duration: "2 hours" ---- - -## Prerequisites - -This guide is based on Prisma's [introspection](./introspection.md) feature which is constantly being improved. Right now, it still has the following limitations: - -- Every column needs to have a primary key constraint on a single column ([multi-column primary keys are not yet supported](https://github.com/prisma/prisma-client-js/issues/339)). Introspection will fail if this is not the case. Note that this often makes it impossible to introspect a schema that uses relation tables (also sometimes called "join tables") as these typically don't have a single-column primary key. -- `ENUM` types are not yet supported. Introspection will succeed and ignore the `ENUM` types in your database schema. -- `TIMESTAMP WITH TIMEZONE` types are already supported via introspection (and mapped to Prisma's `DateTime` type) but [currently can't be queried with Prisma Client](https://github.com/prisma/prisma2/issues/1386). - -## 1. Set up Prisma for your database - -First, run the following command to create an empty Prisma schema file: - -```bash copy -npx prisma2 init -``` - - - -```bash copy -brew tap prisma/prisma -brew install prisma -``` - -```bash copy -npm install -g prisma -``` - - - -This creates an empty Prisma schema looking similar to this: - -```js -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -// The `datasource` block is used to specify the connection to your DB. -// Set the `provider` field to match your DB type: "postgresql", "mysql" or "sqlite". -// The `url` field must contain the connection string to your DB. -// Learn more about connection strings for your DB: https://pris.ly/d/connection-strings -datasource db { - provider = "postgresql" // other options are: "mysql" and "sqlite" - url = "postgresql://johndoe:johndoe@localhost:5432/mydb?schema=public" -} -// Other examples for connection strings are: -// SQLite: url = "sqlite:./dev.db" -// MySQL: url = "mysql://johndoe:johndoe@localhost:3306/mydb" -// You can also use environment variables to specify the connection string: -// https://pris.ly/d/prisma-schema#using-environment-variables - -// By adding the `generator` block, you specify that you want to generate Prisma's DB client. -// The client is generated by runnning the `prisma generate` command -// and will be located in `node_modules/@prisma` and can be imported in your code as: -// import { PrismaClient } from '@prisma/client' -generator client { - provider = "prisma-client-js" -} - -// Next steps: -// 1. Add your DB connection string as the `url` of the `datasource` block -// 2. Run `prisma2 introspect` to get your data model into the schema -// 3. Run `prisma2 generate` to generate Prisma Client JS -// 4. Start using Prisma Client JS in your application -``` - -This file contains a number of comments that tell you how to proceed. - -First you need to provide the connection URL of your database as the `url` of the `datasource` block. This is needed so that Prisma can introspect your database schema and generate Prisma Client. - -The format of the connection URL for your database typically depends on the database you use (the parts spelled all-uppercased are placeholders for your specific connection details): - -- MySQL: `mysql://USER:PASSWORD@HOST:PORT/DATABASE` -- PostgreSQL: `postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=SCHEMA` -- SQLite: `sqlite:./FILE.db` - - -When running PostgreSQL locally, your user and password as well as the database name typically correspond to the current _user_ of your OS, e.g.: - -```prisma -datasource db { - provider = "postgresql" - url = "postgresql://janedoe:janedoe@localhost:5432/janedoe?schema=hello-prisma2" -} -``` - -> **Note**: If you're unsure what to provide for the `schema` parameter for a PostgreSQL connection URL, you can probably omit it. In that case, the default schema name `public` will be used. - - -## 2. Introspect your database to generate a data model - -The next step is to run Prisma's introspection to obtain your data model: - -```bash -npx prisma2 introspect -``` - -> **Note**: If Prisma's introspection failed for your database schema, please [open an issue](https://github.com/prisma/prisma2/issues/new) and tell us what went wrong. If you want to help us make Prisma more resilient, please [share your database SQL schema with us](https://github.com/prisma/prisma2/issues/757) so we can add it to our introspection testing suite. - -This command connects to your database and introspects its schema. Based on that schema, Prisma then adds a number of models to your Prisma schema file which represent the data model of your application. This data model will be the foundation for the generated data access API of Prisma Client. - -For the purpose of this guide, we're using the following SQL schema: - -```sql -CREATE TABLE users ( - user_id SERIAL PRIMARY KEY NOT NULL, - name VARCHAR(256), - email VARCHAR(256) UNIQUE NOT NULL -); - -CREATE TABLE posts ( - post_id SERIAL PRIMARY KEY NOT NULL, - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - title VARCHAR(256) NOT NULL, - content TEXT, - author_id INTEGER REFERENCES users(user_id) -); - -CREATE TABLE profiles ( - profile_id SERIAL PRIMARY KEY NOT NULL, - bio TEXT, - user_id INTEGER NOT NULL REFERENCES users(user_id) -); -``` - -Prisma's introspection generates the following data model for the SQL schema above: - -```prisma -model posts { - author_id users? - content String? - created_at DateTime? - post_id Int @id - title String -} - -model profiles { - bio String? - profile_id Int @id - user_id users -} - -model users { - email String @unique - name String? - user_id Int @id - postses posts[] - profileses profiles[] -} -``` - -> **Note**: The wrong pluralization of `posts` and `profiles` to `postses` and `profileses` [will be fixed soon](https://github.com/prisma/prisma2/issues/1109). - -## 3. Generate Prisma Client - -Prisma Client is an auto-generated and type-safe database client that's tailored to your database schema. Note that you'll need a Node.js/TypeScript project in order to generate Prisma Client since it relies the `@prisma/client` dependency. You'll use TypeScript for the purpose of this guide. - -If you don't have one already, run the following commands to create a simple TypeScript setup: - -```bash -npm init -y -npm install typescript ts-node --save-dev -npm install @prisma/client -touch script.ts -touch tsconfig.json -``` - -Next, add the following contents to your `tsconfig.json`: - -```json -{ - "compilerOptions": { - "outDir": "dist", - "rootDir": "src", - "lib": ["esnext"], - "strict": true - }, - "include": ["src/**/*"] -} -``` - -Now you can generate Prisma Client: - -```bash -npx prisma2 generate -``` - -Your Prisma Client API is now ready to be used in `node_modules/@prisma/client`. - -## 4. Use Prisma Client to read and write data in your database - -With your TypeScript setup in place, add the following code to `script.ts`: - -```ts -import { PrismaClient } from '@prisma/client' - -const prisma = new PrismaClient() - -async function main() { - - const users = await prisma.user.findMany({ - include: { - postses: true, - } - }) - console.log(JSON.stringify(users)) -} - -main() -``` - -This is a simple API call that fetches all the records from the `users` table. you can run the script with this command: - -```bash -npx ts-node script.ts -``` - -If you've used your own database in this guide and are unsure what to query for, you can use your editor's auto-complection feature to help create a query by typing `prisma.` and then hit CTRL+SPACE to suggest any of your models as a starting point for the query. Once you selected a model and added another dot afterwards, you can again use the CTRL+SPACE to decide for an operation on the model (e.g. `findMany`, `create`, `update`, ...). After having selected the operation, you can once more invoke the auto-completion to explore the arguments to provide for the operation. - -![](https://imgur.com/p4kdfhH.gif) diff --git a/content/02-understand-prisma/01-introduction.mdx b/content/02-understand-prisma/01-introduction.mdx new file mode 100644 index 0000000000..9c336ee16b --- /dev/null +++ b/content/02-understand-prisma/01-introduction.mdx @@ -0,0 +1,7 @@ +--- + title: "Introduction" + metaTitle: "" + metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/02-understand-prisma/02-features.mdx b/content/02-understand-prisma/02-features.mdx new file mode 100644 index 0000000000..72901831d9 --- /dev/null +++ b/content/02-understand-prisma/02-features.mdx @@ -0,0 +1,121 @@ +--- + title: "Features" + metaTitle: "" + metaDescription: "" +--- + +**Note: The content of this page is still in progress.** + +## Relational databases + +### Constraints + +| Constraint | PostgreSQL | MySQL | SQLite | ◭ Prisma schema | ◭ Prisma Migrate | ◭ Prisma Client | +| ------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------- | ---------------- | --------------- | +| `PRIMARY KEY` | Yes | Yes | Yes | `@id` and `@@id` | Yes | Yes | +| `FOREIGN KEY` | [Yes](./guides/database-workflows/foreign-keys/postgresql.md) | [Yes](./guides/database-workflows/foreign-keys/mysql.md) | [Yes](./guides/database-workflows/foreign-keys/sqlite.md) | Relation between Prisma models | Yes | Yes | +| `UNIQUE` | [Yes](./guides/database-workflows/unique-constraints-and-indexes/postgresql.md) | [Yes](./guides/database-workflows/unique-constraints-and-indexes/mysql.md) | [Yes](./guides/database-workflows/unique-constraints-and-indexes/sqlite.md) | `@unique` and `@@unique` | Yes | Yes | +| `CHECK` | Yes | In [MySQL 8 and higher](https://mysqlserverteam.com/mysql-8-0-16-introducing-check-constraint/) | Yes | Not yet | Not yet | Yes | +| `NOT NULL` | Yes | Yes | Yes | `?` following the type of a Prisma model | Yes | Yes | + +### Deletion behaviors (for foreign key references) + +| Deletion behavior | PostgreSQL | MySQL | SQLite | ◭ Prisma schema | ◭ Prisma Migrate | ◭ Prisma Client | +| ----------------- | ------------------------------------------------------------------ | ------------------------------------------------------------- | -------------------------------------------------------------- | --------------- | ---------------- | --------------- | +| `CASCADE` | [Yes](./guides/database-workflows/cascading-deletes/postgresql.md) | [Yes](./guides/database-workflows/cascading-deletes/mysql.md) | [Yes](./guides/database-workflows/cascading-deletes/sqlite.md) | Not yet | Not yet | Yes | +| `RESTRICT` | [Yes](./guides/database-workflows/cascading-deletes/postgresql.md) | [Yes](./guides/database-workflows/cascading-deletes/mysql.md) | [Yes](./guides/database-workflows/cascading-deletes/sqlite.md) | Not yet | Not yet | Yes | +| `NO ACTION` | [Yes](./guides/database-workflows/cascading-deletes/postgresql.md) | [Yes](./guides/database-workflows/cascading-deletes/mysql.md) | [Yes](./guides/database-workflows/cascading-deletes/sqlite.md) | Not yet | Not yet | Yes | +| `SET DEFAULT` | [Yes](./guides/database-workflows/cascading-deletes/postgresql.md) | [Yes](./guides/database-workflows/cascading-deletes/mysql.md) | [Yes](./guides/database-workflows/cascading-deletes/sqlite.md) | Not yet | Not yet | Yes | +| `SET NULL` | [Yes](./guides/database-workflows/cascading-deletes/postgresql.md) | [Yes](./guides/database-workflows/cascading-deletes/mysql.md) | [Yes](./guides/database-workflows/cascading-deletes/sqlite.md) | Not yet | Not yet | Yes | + +### Update behaviors (for foreign key references) + +| Update behavior | PostgreSQL | MySQL | SQLite | ◭ Prisma schema | ◭ Prisma Migrate | ◭ Prisma Client | +| --------------- | ---------- | ----- | ------ | --------------- | ---------------- | --------------- | +| `CASCADE` | Yes | Yes | Yes | Not yet | Not yet | Yes | +| `RESTRICT` | Yes | Yes | Yes | Not yet | Not yet | Yes | +| `NO ACTION` | Yes | Yes | Yes | Not yet | Not yet | Yes | +| `SET DEFAULT` | Yes | Yes | Yes | Not yet | Not yet | Yes | +| `SET NULL` | Yes | Yes | Yes | Not yet | Not yet | Yes | + +### Indexes + +| Index | PostgreSQL | MySQL | SQLite | ◭ Prisma schema | ◭ Prisma Migrate | ◭ Prisma Client | +| ----------------------- | ------------------------------------------------------------------------------- | ----- | ------ | ------------------------ | ---------------- | --------------- | +| `UNIQUE` | [Yes](./guides/database-workflows/unique-constraints-and-indexes/postgresql.md) | Yes | Yes | `@unique` and `@@unique` | Not yet | Yes | +| `FULLTEXT` | | Yes | | | Not yet | Yes | +| `SPATIAL` | | Yes | | | Not yet | Yes | +| `WHERE` (partial index) | Yes | Yes | Yes | Not yet | Not yet | Yes | +| `USING` | Yes | Yes | Yes | Not yet | Not yet | Yes | + +Algorithm specified via `USING`: + +| Index type (Algorithm) | PostgreSQL | MySQL | SQLite | ◭ Prisma schema | ◭ Prisma Migrate | ◭ Prisma Client | +| ---------------------- | ---------- | ----- | ------ | --------------- | ---------------- | --------------- | +| B-tree | Yes | Yes | Yes | Not yet | Not yet | Yes | +| Hash | Yes | Yes | Yes | Not yet | Not yet | Yes | +| GiST | Yes | No | No | Not yet | Not yet | Yes | +| GIN | Yes | No | No | Not yet | Not yet | Yes | +| BRIN | Yes | No | No | Not yet | Not yet | Yes | +| SP-GiST | Yes | No | No | Not yet | Not yet | Yes | + +**MySQL only** + +Algorithm option (MySQL): + +| Index type (Algorithm) | MySQL | ◭ Prisma schema | ◭ Prisma Migrate | ◭ Prisma Client | +| ---------------------- | ----- | --------------- | ---------------- | --------------- | +| `INPLACE` | Yes | Not yet | Not yet | Yes | +| `COPY` | Yes | Not yet | Not yet | Yes | + +Lock option (MySQL): + +| Index type (Algorithm) | MySQL | ◭ Prisma schema | ◭ Prisma Migrate | ◭ Prisma Client | +| ---------------------- | ----- | --------------- | ---------------- | --------------- | +| `NONE` | Yes | Not yet | Not yet | Yes | +| `EXCLUSIVE` | Yes | Not yet | Not yet | Yes | +| `SHARED` | Yes | Not yet | Not yet | Yes | + +## Functions + +| Name | PostgreSQL | MySQL | SQLite | +| ----------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `uuid()` | Yes (via an [extension](http://www.ossp.org/pkg/lib/uuid/)) | Yes (but usage as default values only in [MySQL 8 and higher](https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html)) | No | +| `cuid()` | No | No | No | +| `autoincrement()` | Yes (via the `SERIAL` type) | Yes (via the `AUTO_INCREMENT` keyword) | Yes (via the `AUTOINCREMENT` keyword) | +| `now()` | Yes | Yes | Yes (e.g. via `date('now')`) | + +### Misc + +| Feature | PostgreSQL | MySQL | SQLite | ◭ Prisma schema | ◭ Prisma Migrate | ◭ Prisma Client | +| --------------------------------- | ---------- | ----- | ------ | ------------------------------------------------ | ---------------------------------- | --------------- | +| Native database types | Yes | Yes | Yes | Not yet | Not yet | Yes | +| Arrays (native scalar lists) | Yes | No | No | `[]` following the scalar type of a Prisma model | Yes (if supported by the database) | Yes | +| Enums | Yes | Yes | No | Declared in `enum` blocks | Yes (if supported by the database) | Yes | +| Views | Yes | Yes | Yes | Not yet | Not yet | No | +| Authorization and user management | Yes | Yes | No | Not yet | Not yet | Not yet | +| JSON support | Yes | No | No | Not yet | Not yet | Not yet | +| Fuzzy/Phrase Full Text Search | Yes | Yes | No | Not yet | Not yet | Not yet | + +## Type mappings between Prisma and database + +TBD for different scenarios: + +- Introspection +- Migrations +- Raw SQL + +## Queries (Prisma Client API) + +- eager and lazy loading +- field selection +- raw database access +- advanced filter api on relations +- fully type-safe +- filtering +- ordering +- pagination +- uni-directional, bi-directional and self-referenced relations +- transactions +- connection handling +- aggregations diff --git a/content/02-understand-prisma/index.mdx b/content/02-understand-prisma/index.mdx new file mode 100644 index 0000000000..eb0bd30890 --- /dev/null +++ b/content/02-understand-prisma/index.mdx @@ -0,0 +1,6 @@ +--- + title: "Understand Prisma" + metaTitle: "Understand Prisma" + metaDescription: "Understand Prisma" +--- + diff --git a/content/02-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx similarity index 100% rename from content/02-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx rename to content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx diff --git a/content/02-reference/01-tools-and-interfaces/01-schema/02-data-model.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/02-data-model.mdx similarity index 100% rename from content/02-reference/01-tools-and-interfaces/01-schema/02-data-model.mdx rename to content/03-reference/01-tools-and-interfaces/01-schema/02-data-model.mdx diff --git a/content/02-reference/01-tools-and-interfaces/01-schema/03-connectors.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/03-connectors.mdx similarity index 100% rename from content/02-reference/01-tools-and-interfaces/01-schema/03-connectors.mdx rename to content/03-reference/01-tools-and-interfaces/01-schema/03-connectors.mdx diff --git a/content/02-reference/01-tools-and-interfaces/01-schema/04-generators.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/04-generators.mdx similarity index 100% rename from content/02-reference/01-tools-and-interfaces/01-schema/04-generators.mdx rename to content/03-reference/01-tools-and-interfaces/01-schema/04-generators.mdx diff --git a/content/02-reference/01-tools-and-interfaces/01-schema/05-environment-variables.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/05-environment-variables.mdx similarity index 100% rename from content/02-reference/01-tools-and-interfaces/01-schema/05-environment-variables.mdx rename to content/03-reference/01-tools-and-interfaces/01-schema/05-environment-variables.mdx diff --git a/content/02-reference/01-tools-and-interfaces/01-schema/index.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx similarity index 100% rename from content/02-reference/01-tools-and-interfaces/01-schema/index.mdx rename to content/03-reference/01-tools-and-interfaces/01-schema/index.mdx diff --git a/content/02-reference/01-tools-and-interfaces/02-introspection.mdx b/content/03-reference/01-tools-and-interfaces/02-introspection.mdx similarity index 100% rename from content/02-reference/01-tools-and-interfaces/02-introspection.mdx rename to content/03-reference/01-tools-and-interfaces/02-introspection.mdx diff --git a/content/02-reference/01-tools-and-interfaces/index.mdx b/content/03-reference/01-tools-and-interfaces/index.mdx similarity index 100% rename from content/02-reference/01-tools-and-interfaces/index.mdx rename to content/03-reference/01-tools-and-interfaces/index.mdx diff --git a/content/02-reference/02-more/01-roadmap.mdx b/content/03-reference/02-more/01-roadmap.mdx similarity index 100% rename from content/02-reference/02-more/01-roadmap.mdx rename to content/03-reference/02-more/01-roadmap.mdx diff --git a/content/02-reference/02-more/index.mdx b/content/03-reference/02-more/index.mdx similarity index 100% rename from content/02-reference/02-more/index.mdx rename to content/03-reference/02-more/index.mdx diff --git a/content/02-reference/index.mdx b/content/03-reference/index.mdx similarity index 100% rename from content/02-reference/index.mdx rename to content/03-reference/index.mdx diff --git a/yarn.lock b/yarn.lock index 4d85f17775..7f75a6bfba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1993,11 +1993,6 @@ abab@^2.0.0: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - accepts@^1.3.7, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -4665,7 +4660,7 @@ detect-indent@^6.0.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd" integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA== -detect-libc@^1.0.2, detect-libc@^1.0.3: +detect-libc@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= @@ -6147,13 +6142,6 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -7605,7 +7593,7 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== -iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -7639,13 +7627,6 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -ignore-walk@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - dependencies: - minimatch "^3.0.4" - ignore@^3.3.5: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" @@ -10057,14 +10038,6 @@ minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - minipass@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" @@ -10072,13 +10045,6 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - minizlib@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.0.tgz#fd52c645301ef09a63a2c209697c294c6ce02cf3" @@ -10231,15 +10197,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -needle@^2.2.1: - version "2.3.3" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.3.tgz#a041ad1d04a871b0ebb666f40baaf1fb47867117" - integrity sha512-EkY0GeSq87rWp1hoq/sH/wnTWgFVhYlnIkbJ0YJFfRgEFlz2RraCjBpFQ+vrEgEdp0ThfyHADmkChEhcb7PKyw== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -10369,22 +10326,6 @@ node-object-hash@^2.0.0: resolved "https://registry.yarnpkg.com/node-object-hash/-/node-object-hash-2.0.0.tgz#9971fcdb7d254f05016bd9ccf508352bee11116b" integrity sha512-VZR0zroAusy1ETZMZiGeLkdu50LGjG5U1KHZqTruqtTyQ2wfWhHG2Ow4nsUbfTFGlaREgNHcCWoM/OzEm6p+NQ== -node-pre-gyp@*: - version "0.14.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" - integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4.4.2" - node-releases@^1.1.29, node-releases@^1.1.52: version "1.1.52" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.52.tgz#bcffee3e0a758e92e44ecfaecd0a47554b0bcba9" @@ -10405,14 +10346,6 @@ noop-logger@^0.1.1: resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= -nopt@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" - integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== - dependencies: - abbrev "1" - osenv "^0.1.4" - normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -10469,13 +10402,6 @@ normalize-url@^4.1.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== -npm-bundled@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" - integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== - dependencies: - npm-normalize-package-bin "^1.0.1" - npm-conf@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" @@ -10484,20 +10410,6 @@ npm-conf@^1.1.0: config-chain "^1.1.11" pify "^3.0.0" -npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - -npm-packlist@^1.1.6: - version "1.4.8" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" - integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - npm-normalize-package-bin "^1.0.1" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -10512,7 +10424,7 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" -npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2: +npmlog@^4.0.1, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -10773,7 +10685,7 @@ os-filter-obj@^2.0.0: dependencies: arch "^2.1.0" -os-homedir@^1.0.0, os-homedir@^1.0.1: +os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= @@ -10787,19 +10699,11 @@ os-locale@^3.0.0: lcid "^2.0.0" mem "^4.0.0" -os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: +os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - p-cancelable@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" @@ -14173,19 +14077,6 @@ tar-stream@^2.0.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^4.4.2: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - tar@^5.0.5: version "5.0.5" resolved "https://registry.yarnpkg.com/tar/-/tar-5.0.5.tgz#03fcdb7105bc8ea3ce6c86642b9c942495b04f93" @@ -15748,7 +15639,7 @@ yallist@^2.0.0, yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: +yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== From 04856c2dcdc9c7cd87ce13ce1e60fb453f37d773 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Fri, 20 Mar 2020 15:44:58 +0100 Subject: [PATCH 02/33] add understand prisma content --- .../01-add-to-an-existing-project.mdx | 1 + content/02-understand-prisma/02-features.mdx | 20 +- .../01-rest.md | 7 + .../02-graphql.md | 80 ++++ .../index.mdx | 6 + .../04-is-prisma-an-orm.mdx | 363 ++++++++++++++++++ .../02-understand-prisma/05-data-modeling.mdx | 232 +++++++++++ content/02-understand-prisma/user-table.svg | 3 + 8 files changed, 703 insertions(+), 9 deletions(-) create mode 100644 content/02-understand-prisma/03-how-prisma-fits-into-your-stack/01-rest.md create mode 100644 content/02-understand-prisma/03-how-prisma-fits-into-your-stack/02-graphql.md create mode 100644 content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx create mode 100644 content/02-understand-prisma/04-is-prisma-an-orm.mdx create mode 100644 content/02-understand-prisma/05-data-modeling.mdx create mode 100644 content/02-understand-prisma/user-table.svg diff --git a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx index 8730448c16..c6a7070837 100644 --- a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx +++ b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx @@ -5,6 +5,7 @@ --- ## Overview + **Note: The content of this page is temporary and will be updated soon.** This page explains how to get started with Prisma in an existing project. diff --git a/content/02-understand-prisma/02-features.mdx b/content/02-understand-prisma/02-features.mdx index 72901831d9..72e81f810e 100644 --- a/content/02-understand-prisma/02-features.mdx +++ b/content/02-understand-prisma/02-features.mdx @@ -75,15 +75,7 @@ Lock option (MySQL): | `NONE` | Yes | Not yet | Not yet | Yes | | `EXCLUSIVE` | Yes | Not yet | Not yet | Yes | | `SHARED` | Yes | Not yet | Not yet | Yes | - -## Functions - -| Name | PostgreSQL | MySQL | SQLite | -| ----------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | -| `uuid()` | Yes (via an [extension](http://www.ossp.org/pkg/lib/uuid/)) | Yes (but usage as default values only in [MySQL 8 and higher](https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html)) | No | -| `cuid()` | No | No | No | -| `autoincrement()` | Yes (via the `SERIAL` type) | Yes (via the `AUTO_INCREMENT` keyword) | Yes (via the `AUTOINCREMENT` keyword) | -| `now()` | Yes | Yes | Yes (e.g. via `date('now')`) | + | Yes (e.g. via `date('now')`) | ### Misc @@ -97,6 +89,16 @@ Lock option (MySQL): | JSON support | Yes | No | No | Not yet | Not yet | Not yet | | Fuzzy/Phrase Full Text Search | Yes | Yes | No | Not yet | Not yet | Not yet | + + +## Functions + +| Name | PostgreSQL | MySQL | SQLite | +| ----------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `uuid()` | Yes (via an [extension](http://www.ossp.org/pkg/lib/uuid/)) | Yes (but usage as default values only in [MySQL 8 and higher](https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html)) | No | +| `cuid()` | No | No | No | +| `autoincrement()` | Yes (via the `SERIAL` type) | Yes (via the `AUTO_INCREMENT` keyword) | Yes (via the `AUTOINCREMENT` keyword) | +| `now()` | Yes | Yes ## Type mappings between Prisma and database TBD for different scenarios: diff --git a/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/01-rest.md b/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/01-rest.md new file mode 100644 index 0000000000..81188de40f --- /dev/null +++ b/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/01-rest.md @@ -0,0 +1,7 @@ +--- + title: "REST" + metaTitle: "" + metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/02-graphql.md b/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/02-graphql.md new file mode 100644 index 0000000000..0c7e97aabc --- /dev/null +++ b/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/02-graphql.md @@ -0,0 +1,80 @@ +--- + title: "GraphQL" + metaTitle: "" + metaDescription: "" +--- + +**Note: The content of this page is still in progress.** + +## Overview + +GraphQL is a query language for APIs. It is often used as an alternative to RESTful APIs, but can also be used as an additional "gateway" layer on top of existing RESTful services. + +With Prisma, you can build GraphQL servers that connect to a database. Prisma is completely agnostic to the GraphQL tools you use. When building as GraphQL server, you can combine Prisma with tools like Apollo Server, `express-graphql`, TypeGraphQL, GraphQL.js or pretty much any tool or library that you're using in your GraphQL server setup. + +## GraphQL servers under the hood + +A GraphQL server consists of two major components: + +- GraphQL schema (type definitions + resolvers) +- HTTP server + +Note that a GraphQL schema can be written code-first or SDL-first. Check out this [article](https://www.prisma.io/blog/the-problems-of-schema-first-graphql-development-x1mn4cb0tyl3/) to learn more about these two approaches. If you like the SDL-first approach but still want to make your code type safe, check out [GraphQL Code Generator](https://graphql-code-generator.com/) to generate various type definitions based on SDL. + +The GraphQL schema and HTTP server are typically handled by separate libraries. Here is an overview of current GraphQL server tools and their purpose: + +| Library (npm package) | Purpose | Compatible with Prisma | Prisma integration | +| :-------------------- | :-------------------------- | :--------------------- | :----------------- | +| `graphql` | GraphQL schema (code-first) | Yes | No | +| `graphql-tools` | GraphQL schema (SDL-first) | Yes | No | +| `type-graphql` | GraphQL schema (code-first) | Yes | In progress | +| `apollo-server` | HTTP server | Yes | n/a | +| `express-graphql` | HTTP server | Yes | n/a | +| `fastify-gql` | HTTP server | Yes | n/a | +| `graphql-yoga` | HTTP server | Yes | n/a | + +In addition to these standalone and single-purpose libraries, there are several projects building integrated _application frameworks_: + +| Framework | Stack | Built by | Prisma | Description | +| :----------------------------------------- | :--------------- | :------------------------------------------------ | :--------------------- | :---- | +| [Nexus](https://www.nexusjs.org/#/) | Backend only | [Prisma Labs](https://github.com/prisma-labs/) | Prisma is optional | "Delightful GraphQL Application Framework" | +| [Redwood.js](https://redwoodjs.com) | Fullstack | [Tom Preston-Werner](https://github.com/mojombo/) | Built on top of Prisma | "Bringing full-stack to the JAMstack. " | +| [Blitz](https://github.com/blitz-js/blitz) | Fullstack | [Brandon Bayer](https://github.com/flybayer) | Built on top of Prisma | "Framework for building monolithic, full-stack, serverless React apps with zero data-fetching and zero client-side state management." | + +> **Note**: If you notive any GraphQL libraries/frameworks missing from the list, please let us know. + +## Prisma & GraphQL examples + +Below you find a number of ready-to-run examples that showcase how to use Prisma with different combination of the tools mentioned in the table above. + +### TypeScript + +| Demo | HTTP Server | GraphQL schema | Description | +| :----------------------------------------------------------------------------------------------------------------- | :-------------- | :-------------- | :------------------------------------------------------------------------------------------------------------------------------------- | +| [GraphQL](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/graphql) | `graphql-yoga` | `nexus` | Simple GraphQL server based on [`graphql-yoga`](https://github.com/prisma-labs/graphql-yoga) | +| [GraphQL (Apollo Server)](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/graphql-apollo-server) | `apollo-server` | `nexus` | Simple GraphQL server based on [`apollo-server`](https://www.apollographql.com/docs/apollo-server/) | +| [GraphQL (SDL-first)](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/graphql-sdl-first) | `graphql-yoga` | `graphql-tools` | Simple GraphQL server based on the SDL-first approach of [`graphql-tools`](https://www.apollographql.com/docs/graphql-tools/) (Apollo) | +| [GraphQL (Auth)](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/graphql-auth) | `graphql-yoga` | `nexus` | GraphQL server with email-password authentication & permissions | + +### JavaScript (Node.js) + +| Demo | HTTP Server | GraphQL schema | Description | +| :----------------------------------------------------------------------------------------------------------------- | :-------------- | :-------------- | :------------------------------------------------------------------------------------------------------------------------------------- | +| [GraphQL](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/graphql) | `graphql-yoga` | `nexus` | Simple GraphQL server based on [`graphql-yoga`](https://github.com/prisma-labs/graphql-yoga) | +| [GraphQL (Apollo Server)](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/graphql-apollo-server) | `apollo-server` | `nexus` | Simple GraphQL server based on [`apollo-server`](https://www.apollographql.com/docs/apollo-server/) | +| [GraphQL (SDL-first)](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/graphql-sdl-first) | `graphql-yoga` | `graphql-tools` | Simple GraphQL server based on the SDL-first approach of [`graphql-tools`](https://www.apollographql.com/docs/graphql-tools/) (Apollo) | +| [GraphQL (Auth)](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/graphql-auth) | `graphql-yoga` | `nexus` | GraphQL server with email-password authentication & permissions | + +## FAQ + +### What is Prisma's role in a GraphQL server? + +No matter which of the above GraphQL tools/libraries you use, Prisma is used inside your GraphQL resolvers to connect to your database. It has the same role that any other ORM or SQL query builder would have inside your resolvers. + +In the resolver of a GraphQL query, Prisma typically reads data from the database to return it in the GraphQL response. In the resolver of a GraphQL mutation, Prisma typically also writes data to the database (e.g. creating new or updating existing records). + +### Is there a special connection between Prisma and Nexus? + +Yes. At Prisma, we love GraphQL and strongly believe in its bright future. While Prisma is compatible with all tools from the GraphQL ecosystem, we want to leverage the amazing things that become possible when Nexus and Prisma are combined and are therefore helping to build it. + +The [Prisma Labs]() team has been founded as an independent part of the rest of Prisma's engineering organization to work on open-source tools that are not directly tied to the Prisma database tools. Prisma Labs is currently dedicating most of their time to work on Nexus with the vision of making it a fully-fledged backend framework for building GraphQL servers. diff --git a/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx b/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx new file mode 100644 index 0000000000..86c951be1b --- /dev/null +++ b/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx @@ -0,0 +1,6 @@ +--- + title: "How Prisma fits into your stack" + metaTitle: "How Prisma fits into your stack" + metaDescription: "How Prisma fits into your stack" +--- + diff --git a/content/02-understand-prisma/04-is-prisma-an-orm.mdx b/content/02-understand-prisma/04-is-prisma-an-orm.mdx new file mode 100644 index 0000000000..0dd377124c --- /dev/null +++ b/content/02-understand-prisma/04-is-prisma-an-orm.mdx @@ -0,0 +1,363 @@ +--- + title: "Is Prisma an ORM?" + metaTitle: "" + metaDescription: "" +--- + +## Overview + + +To answer the question briefly: _No, Prisma is not an ORM_. + +If you're looking for an Object-Relational-Mapper (ORM), Prisma may help you. While Prisma shares the same goals with ORMs, it takes a different approach. + +ORMs and Prisma are both database abstractions that share the goal of making it easy to work with relational databases. + +Prisma is not considered an ORM because it doesn't map classes to tables the way ORMs do. + +To understand how they differ, here's a brief overview of how their building blocks relate to databases: + +| Database | ORMs | Prisma | +| ---------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------- | +| Tables | Model classes | Models in the Prisma schema | +| Columns | Properties in model classes | Model fields in the [Prisma schema](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md) | +| Records | Instances of a model class (objects) | Plain JavaScript objects | +| SQL Schema | Migrations and model classes | Prisma schema | + +For a more detailed explanation follow along. + +## What are ORMs? + +If you're already familiar with ORMs, feel free to jump to the [next section](#prisma) on Prisma. + +### Concepts + +ORMs provide a high-level database abstraction. They expose a programmatic interface to create, read, delete, and manipulate data while hiding some of the complexity of the database. Database abstractions vary in terms of the complexity they hide and the approach they take (for example, query builders like [knex.js](https://knexjs.org/) and [MassiveJS](https://massivejs.org/)). + +The idea with ORMs is that you define your models as **classes** that map to tables in a database. The classes and their instances provide you with a flexible API to read and write data in the database. + +Database records are represented as instances of the model classes which carry the logic for storage, retrieval, serialization, and deserialization. They often also contain business logic. + +Model classes typically have several responsibilities: + +- Mapping the table's columns to the model's properties, e.g. mapping a `createdAt` column to a `createdAt` property on your model. +- Mapping the foreign keys in a table to relations of the corresponding models, e.g. a 1:n relationship between a `blog` and `posts` as represented by a `blog_id` field in the posts table. +- Implementing business/domain logic e.g. `isUserEmailConfirmed` method to check whether the account's email has been confirmed. + +### Workflows + +[Sequelize](https://sequelize.org/) is a popular ORM in the Node.js ecosystem. Like most ORMs, Sequelize supports workflows for data modeling, querying, and schema migrations. + +#### Data modeling + +For example, assume a hypothetical `User` table: + +![user-table](https://imgur.com/6fWGyNY.png) + +The equivalent SQL in PostgreSQL dialect: + +```SQL +CREATE TABLE "public"."User" ( + id SERIAL PRIMARY KEY NOT NULL, + first_name VARCHAR(255), + last_name VARCHAR(255), + email VARCHAR(255) UNIQUE NOT NULL, + email_confirmed BOOLEAN NOT NULL DEFAULT FALSE, + birth_date DATE NOT NULL, +); +``` + +Here's what its corresponding model class will look like with Sequelize. +You define the model's fields, map them to the table's fields, and define a class and instance method: + +```js +import { Model } from 'sequelize' + +class User extends Model { + // Class method that can be called directly on the model class + static async isEmailConfirmed(email) { + const count = await this.count({ where: { email, emailConfirmed: true } }) + return count === 0 + } + // Model instance method + getFullName() { + return [this.firstname, this.lastname].join(' ') + } +} + +User.init( + { + id: { + allowNull: false + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + } + firstName: { + type: Sequelize.STRING, + field: 'first_name', + allowNull: true + }, + lastName: { + type: Sequelize.STRING, + field: 'last_name', + allowNull: true + }, + email: { + type: Sequelize.STRING, + allowNull: false, + unique: true, + validate: { + isEmail: true + } + }, + emailConfirmed: { + type: Sequelize.BOOLEAN, + field: 'email_confirmed', + allowNull: false, + defaultValue: false + }, + birthDate: { + type: Sequelize.DATE, + field: 'birth_date' + } + }, + { sequelize } +) +``` + +Model instances represent database records and contain three important things: + +- The in-memory representation of the record data as persisted in the database +- The logic for storage, retrieval, serialization, and deserialization of its data and related data. +- The inherited business/domain logic defined in the model class + +#### Querying + +You can fetch and update a model instance with Sequelize as follows: + +```js +const ada = await User.findOne({ where: { firstName: 'Ada' } }) +ada.lastName = 'Lovelace' +await ada.save() +ada.getFullName() // Ada Lovelace +``` + +#### Schema migrations + +A key part of using a database is changing the schema to accommodate new features and to better fit the problem you're solving. Because the ORM sits between the developer and the database, most ORMs provide a **migration tool** to assist with the creation and modification of the database schema. + +A migration is a set of steps to take the database schema from one state to another. The first migration usually creates tables and indices. Subsequent migrations may alter tables, introduce new indices, or create new tables. Depending on the migration tool, the migration may be in the form of SQL statements or programmatic code which will get converted to SQL statements. + +Sequelize for example, has a programmatic API for migrations. + +Assuming you were starting from scratch, this is what a full workflow would look like: you create a migration that will create the `Users` table in the database schema and define the model class as in the [example above](#data-modeling) with the `User` model. + +1. Create the first migration: + +```js +// migrations/20191217102908-create-user.js +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.createTable('Users', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + firstName: { + type: Sequelize.STRING, + field: 'first_name' + }, + lastName: { + type: Sequelize.STRING, + field: 'last_name' + }, + email: { + type: Sequelize.STRING + }, + emailConfirmed: { + type: Sequelize.BOOLEAN, + field: 'email_confirmed', + allowNull: false, + defaultValue: false + }, + birthDate: { + type: Sequelize.DATE + } + }) + }, + down: (queryInterface, Sequelize) => { + return queryInterface.dropTable('Users') + } +} +``` + +2. Create the corresponding model as in the previous section. +3. To add a new table, create a new migration and corresponding model. + To change the `Users` table, create a new migration which will add the field and update the model to reflect the changes. + +The first two steps will be part of any schema change that uses Sequelize both as an ORM and for migrations. The second step is where the _synchronization culprit_ is. In other words, it is where the responsibility is on the developer to ensure she has correctly defined the model in line with the database schema. + +Other ORMs have a workflow similar to this. Some, like [Django's ORM](https://docs.djangoproject.com/en/3.0/topics/migrations/#workflow), support a simpler workflow where you're required to only change the models and using a CLI tool, your models are scanned and compared to the versions currently contained in your migration files, and then a new set of migrations is be written out. + +Now that you've seen migrations and workflows, you will look at the benefits and drawbacks of ORMs. + +### Benefits of ORMs + +There are different reasons for why developers choose to use ORMs: + +- ORMs facilitate implementing the domain model. The domain model is an object model that incorporates the behavior and data of your business logic. In other words, it allows you to focus on real business concepts rather than the database structure or SQL semantics. +- As you evolve your schema, the changes happen in a single place–the models. This saves you from having to search and replace SQL statements scattered throughout your code. +- ORMs help reduce the amount of code. It saves you from writing repetitive SQL statements for common CRUD (Create Read Update Delete) operations and escaping user input to prevent vulnerabilities such as SQL injections. +- ORMs require you to write little to no SQL (depending on your complexity you may still need to write the odd raw query). This is beneficial for developers who are not familiar with SQL and but still want to work with a database. +- Many ORMs abstract database-specific details. In theory, this means that an ORM can make changing from one database to easier. It should be noted that in practice applications rarely change the database they use. + +As with all abstractions that aim to improve productivity, there are also drawbacks to using ORMs. + +### Drawbacks of ORMs + +The drawbacks of ORMs are not always apparent when you start using them. This section covers some of the commonly accepted ones: + +- With ORMs, you form an object graph representation of database tables; this is known as the [object-relational impedance mismatch](https://en.wikipedia.org/wiki/Object-relational_impedance_mismatch). Depending on your use-case, the problem you are solving may form a complex object graph which doesn't trivially map to a relational database. Synchronizing between two different representations of data, one in the relational database, and the other in-memory (with objects) is quite difficult. This is because objects are more flexible and varied in the way they can relate to each other compared to relational database records. +- While ORMs handle the complexity associated with the problem, the synchronization problem doesn't go away. Any changes to the database schema or the data model require the changes to be mapped back to the other side. This burden is often on the developer. In the context of a team working on a project, database schema changes require coordination. +- ORMs tend to have a large API surface due to the complexity they encapsulate. The flip side of not having to write SQL is that you spend a lot of time learning how to use the ORM. This applies to most abstractions, however without understanding the way the database works, understanding and improving slow queries can be difficult. +- Some _complex queries_ aren't supported by ORMs due to the flexibility that SQL offers. This problem is alleviated by raw SQL querying functionality in which you pass the ORM a SQL statement string and the query is run for you. + +Now that the costs and benefits of ORMs have been covered, you can better understand what Prisma is and how it fits in. + +## Prisma + +Prisma is a **database toolkit** that makes working with databases easy for application developers. It currently consists of two main tools: + +- **Prisma Client**: Auto-generated and type-safe database client +- **Prisma Migrate**: A CLI for declarative data modeling and migrations + +> Note that Prisma Migrate is currently in an experimental state + +Both Prisma Client and Migrate rely on the [_Prisma schema_](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md). The Prisma schema is a declarative representation of your database schema. It serves as the single source truth for both the data model and database schema. + +### How Prisma compares + +Unlike ORMs, with Prisma you don't create model classes nor do you map fields in your codebase to database fields. Instead, you use the generated Prisma Client API like an advanced query builder that returns plain JavaScript objects. Schema changes are synced automatically from the models in the Prisma schema–which serves as a single source of truth– to the database schema. + +Models in Prisma mean something slightly different to ORMs. When using ORMs, models are represented as classes. With Prisma, models are defined in the Prisma schema as abstract entities which describe the relationships between tables: + +```prisma +model User { + id Int @default(autoincrement()) @id + birthDate DateTime + email String @unique + firstName String? + lastName String? + posts Post[] +} + +model Post { + content String? + post_id Int @default(autoincrement()) @id + title String + author_id User +} +``` + +Prima schema's declarative nature is concise compared to imperative model definitions in ORMs. + +The workflow is slightly different to ORMs. You can use Prisma when building new applications from scratch or adopt it incrementally: + +- _Existing application_ (brownfield): Projects that already have a database schema can be introspected by Prisma to generate the Prisma schema and Prisma Client. This use-case works with any existing migration tool and is useful for incremental adoption. It's possible to switch to Prisma Migrate as the migration tool. However, this is optional. +- _New application_ (greenfield): Projects that have no database schema yet can use Prisma Migrate to create the database schema. + +#### Workflow for incremental adoption in projects with an existing database + +Brownfield projects typically already have some database abstraction and schema. Prisma can integrate with such projects by introspecting the existing database to obtain a Prisma schema that reflects the existing database schema and to generate the Prisma Client. This workflow is compatible with any migration tool and ORM which you may already be using. If you prefer to incrementally evaluate and adopt, this approach can be used as part of a [parallel adoption strategy](https://en.wikipedia.org/wiki/Parallel_adoption). + +A non-exhaustive list of setups compatible with this workflow: + +- Projects using plain SQL files with `CREATE TABLE` and `ALTER TABLE` to create and alter the database schema. +- Projects using a third party migration library like [db-migrate](https://github.com/db-migrate/node-db-migrate). +- Projects already using an ORM. In this case, database access through the ORM remains unchanged while the generated Prisma Client can be incrementally adopted. + +In practice, these are the steps necessary to introspect an existing DB and generate Prisma Client: + +1. Create a `schema.prisma` defining the `datasource` (in this case, your existing DB) and `generator`: + +```prisma +datasource db { + provider = "postgresql" + url = "postgresql://janedoe:janedoe@localhost:5432/hello-prisma" +} + +generator client { + provider = "prisma-client-js" +} +``` + +2. Run `prisma2 introspect` +3. Run `prisma2 generate` + +Prisma will generate Prisma Client inside the `node_modules` folder, from which it can be imported in your application. For more extensive usage documentation, see the [Prisma Client API docs](https://github.com/prisma/prisma2/blob/master/docs/prisma-client-js/api.md). + +To summarise, Prisma Client can be integrated into projects with an existing database and tooling as part of a parallel adoption strategy. New projects will use a different workflow detailed next. + +#### Workflow for new projects + +Prisma is different from ORMs in terms of the workflows it supports. A closer look at the steps necessary to create and change a new database schema is useful for understanding Prisma Migrate. + +Prisma Migrate is a CLI for declarative data modeling & migrations. Unlike most migration tools that come as part of an ORM, you only need to describe the current schema, instead of the operations to move from one state to another. Prisma Migrate infers the operations and carries out the migration for you. + +This example demonstrates using Prisma in a new project with a new database schema similar to the Sequelize example above: + +1. Create the Prisma schema: + +```prisma +// schema.prisma +datasource sqlite { + provider = "sqlite" + url = "file:data.db" +} + +generator client { + provider = "prisma-client-js" +} + +model User { + id Int @id + birthDate DateTime + email String @unique + firstName String? + lastName String? +} +``` + +2. `prisma2 migrate save --experimental`: Save the migration. Typically migrations are saved in the code repository +3. `prisma2 migrate up --experimental`: Run the migration which will create the database schema +4. `prisma2 generate`: Re-generate Prisma Client + +For any further changes to the database schema: + +1. Apply changes to the Prisma schema, e.g. add a `registrationDate` field to the `User` model +1. Follow steps 2-4. + +The last two steps demonstrate how declarative migrations work by adding a field to the Prisma schema and using Prisma Migrate to transform the database schema to the desired state. Lastly, the Prisma Client was regenerated so that it reflects the updated schema. + +If you don't want to use Prisma Migrate but still want to use the type-safe generated Prisma Client in a new project, see the next section. + +##### Alternative for new projects without Prisma Migrate + +The workflow above relies on Prisma Migrate, which is still experimental. It is possible to use Prisma Client in a new project with a third-party migration tool instead of Prisma Migrate. For example, a new project could choose to use the Node.js migration framework [db-migrate](https://github.com/db-migrate/node-db-migrate) to create the database schema and migrations and Prisma Client for querying. In essence, this is covered by the [workflow for existing databases](#workflow-for-integration-in-projects-with-existing-databases). + +## Conclusion + +Both Prima and ORMs are powerful tools that aim to make working with databases easier and more productive. + +Like all abstractions, both hide away some of the underlying details of the database with different assumptions. + +The workflow with ORMs is centered around model classes and instances to encapsulate data and related business logic–a pattern fits the OOP (Object Oriented Programming) paradigm. + +Prisma's fundamental differences are the declarative schema as a single source of truth and the use of plain JavaScript objects in Prisma Client. + +These differences and your use case all affect the workflow and cost of adoption. + +Hopefully understanding how they differ can help you make an informed decision. diff --git a/content/02-understand-prisma/05-data-modeling.mdx b/content/02-understand-prisma/05-data-modeling.mdx new file mode 100644 index 0000000000..75ac2c45bd --- /dev/null +++ b/content/02-understand-prisma/05-data-modeling.mdx @@ -0,0 +1,232 @@ +--- + title: "Data modeling with Prisma" + metaTitle: "" + metaDescription: "" +--- + +## What is data modeling? + +The term _data modeling_ refers to the **process of defining the shape and structure of the objects in an application**, these objects are often called "application models". In relational databases (like PostgreSQL), they are stored in _tables_ . When using document databases (like MongoDB), they are stored in _collections_. + +> **Note**: The content on this page is focused on **relational databases**. + +Depending on the domain of your application, the models will be different. For example, if you're writing a blogging application, you might have models such as _blog_, _author_, _article_. When writing a carsharing app, you probably have models like _driver_, _car_, _route_. Application models enable you to represent these different entities in your code by creating respective _data structures_. + +When modeling data, you typically ask questions like: + +- What are the main entities/concepts in my application? +- How do they relate to each other? +- What are their main characteristics/properties? +- How can they be represented with my technology stack? + +## Data modeling without Prisma + +Data modeling typically needs to happen on (at least) two levels: + +- On the **database** level +- On the **application** level (i.e., in your programming language) + +The way how the application models are represented on both levels might differ due to a few reasons: + +- Databases and programming languages use different data types +- Relations are represented differently in a database than in a programming language +- Databases typically have more powerful data modeling capabilities, like indexes, cascading deletes, or a variety of additional constraints (e.g. unique, not null, ...) +- Databases and programming languages have different technical constraints + +### Data modeling on the database level + +On the database level, models are represented via _tables_. For example, you might define a `users` table to store information about the users of your application. Using PostgreSQL, you'd define it as follows: + +```sql +CREATE TABLE users ( + user_id SERIAL PRIMARY KEY NOT NULL, + name VARCHAR(255), + email VARCHAR(255) UNIQUE NOT NULL, + isAdmin BOOLEAN NOT NULL DEFAULT false +); +``` + +A visual representation of the `users` table with some random data might look as follows: + +| `user_id` | `name` | `email` | `isAdmin` | +| :-------- | :------ | :---------------- | :-------- | +| `1` | `Alice` | `alice@prisma.io` | `false` | +| `2` | `Bob` | `bob@prisma.io` | `false` | +| `3` | `Sarah` | `sarah@prisma.io` | `true` | + +It has the following columns: + +- `user_id`: An integer that increments with every new record in the `users` table. It also represents the [primary key](https://en.wikipedia.org/wiki/Primary_key) for each record. +- `name`: A string with at most 255 characters. +- `email`: A string with at most 255 characters. Additionaly, the added constraints express that no two records can have duplicate values for the `email` column, and that _every_ record needs to have a value for it. +- `isAdmin`: A boolean that indicates whether the user has admin rights. + +### Data modeling on the application level + +Additionally to creating the tables that represent the entities from your application domain, you also need to create application models in your programming language. In object-oriented languages, this is often done by creating _classes_ to represent your models. Depending on the programming language, this might also be done with _interfaces_ or _structs_. + +There often is a strong correlation between the tables in your database and the models you define in your code. For example, to represent records from the aforementioned `users` table in your application, you might define a JavaScript (ES6) class looking similar to this: + +```js +class User { + constructor(user_id, name, email, isAdmin) { + this.user_id = user_id + this.name = name + this.email = email + this.isAdmin = isAdmin + } +} +``` + +When using TypeScript, you might define an interface instead: + +```js +interface User { + user_id: Int + name: String + email: String + isAdmin: Boolean +} +``` + +Notice how the `User` model in both cases has the same properties as the `users` table in the previous example. While its often the case that there's a 1:1 mapping between database tables and application models, it can also happen that models are represented completely differently in database and your application. + +With this setup, you can retrieve records from the `users` table and store them instances of your `User` type. The following example code snippet uses [`pg`](https://node-postgres.com/) as the driver for PostgreSQL and creates a `User` instance based on the above defined JavaScript class: + +```js +const resultRows = await client.query('SELECT * FROM users WHERE user_id = 1') +const userData = resultRows[0] +const user = new User( + userData.user_id, + userData.name, + userData.email, + userData.isAdmin, +) +// user = { +// user_id: 1, +// name: "Alice", +// email: "alice@prisma.io", +// isAdmin: false +// } +``` + +Notice that in these examples, the application models are "dumb", meaning they don't implement any logic but their sole purpose is to carry data as plain old JavaScript objects (POJOs). + +### Data modeling with ORMs + +ORMs are commonly used in object-oriented languages to make it easier for developers to work with a database. The key characteristic of an ORM is that it lets you model your application data in terms of _classes_ which are mapped to _tables_ in the underlying database. + +The main difference compared to the approaches explained above is these classes not only carry data, but also implement a substantial amount of logic. Mostly for storage, retrieval, serialization and deserialization, but sometimes they also implement business logic that's specific to your application. + +This means, you don't write SQL statements to read and write data in the database, but instead the instances of your model classes provide an API to store and retrieve data. + +[Sequelize](https://sequelize.org/) is a popular ORM in the Node.js ecosystem, this is how you'd define the same `User` model from the sections before using Sequelize's modeling approach: + +```js +class User extends Model {} +User.init( + { + user_id: { + type: Sequelize.INTEGER, + primaryKey: true, + autoIncrement: true, + }, + name: Sequelize.STRING(255), + email: { + type: Sequelize.STRING(255), + unique: true, + }, + isAdmin: Sequelize.BOOLEAN, + }, + { sequelize, modelName: 'user' }, +) +``` + +To get an example with this `User` class to work, you still need to create the corresponding table in the database. With Sequelize, you have two ways of doing this: + +- Run `User.sync()` (typically not recommended for production) +- Use [Sequelize migrations](https://sequelize.org/v5/manual/migrations.html) to change your database schema + +Note that you'll never instantiate the `User` class manually (using `new User(...)`) as was shown in the previous section, but rather call _static_ methods on the `User` class which then return the `User` model instances: + +```js +const user = await User.findByPk(42) +``` + +The call to `findByPk` creates a SQL statement to retrieve the `User` record that's identified by the ID value `42`. + +The resulting `user` object is an instance of Sequelize's `Model` class (because `User` inherits from `Model`). It's not a POJO, but an object that implements additional behaviour from Sequelize. + +## Data modeling with Prisma + +Depending on which parts of Prisma you want to use in your application, the data modeling flow looks slightly different. The following two sections explain the workflows for using [**only Prisma Client**](#using-only-prisma-client) and using [**Prisma Client and Prisma Migrate (experimental)**](#using-prisma-client-and-prisma-migrate-experimental). + +No matter which approach though, with Prisma you never create application models in your programming language by manually defining classes, interfaces or structs. Instead, the application models are defined in your [Prisma schema](): + +- **Only Prisma Client**: Application models in the Prisma schema are _generated based on the introspection of your database schema_. Data modeling happens primarily on the database-level. +- **Prisma Client and Prisma Migrate (experimental)**: Data modeling happens in the Prisma schema by _manually adding application models_ to it. Prisma Migrate maps these application models to tables in the underlying database. + +As an example, the `User` model from the previous example would be represented as follows in the Prisma schema: + +```prisma +model User { + user_id Int @id @default(autoincrement()) + name String? + email String @unique + isAdmin Boolean @default(false) +} +``` + +Once the application models are in your Prisma schema (whether they were added through introspection or manually by you), the next step typically is to generate Prisma Client which provides a programmatic and type-safe API to read and write data in the shape of your application models. + +Prisma Client JS uses TypeScript [type aliases](http://www.typescriptlang.org/docs/handbook/advanced-types.html#type-aliases) to represent your application models in your code. For example, the `User` model would be represented as follows in the generated Prisma Client JS libary: + +```ts +export declare type User = { + id: number; + name: string | null; + email: string; + isAdmin: boolean; +}; +``` + +Addtionally to the generated types, Prisma Client also provides a data access API that you can use once you've installed the `@prisma/client` package: + +```js +import { PrismaClient } from '@prisma/client' +// or +// const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +// use inside an `async` function to `await` the result +await prisma.user.findOne(...) +await prisma.user.findMany(...) +await prisma.user.create(...) +await prisma.user.update(...) +await prisma.user.delete(...) +await prisma.user.upsert(...) +``` + +### Using only Prisma Client + +When using only Prisma Client and _not_ using Prisma Migrate in your application, data modeling needs to happen on the database level via SQL. Once your SQL schema is ready, you use Prisma's introspection feature to add the application models to your Prisma schema. Finally, you generate Prisma Client which creates the types as well as the programmatic API for you to read and write data in your database. + +Here is an overview of the main workflow: + +1. Change your database schema using SQL (e.g. `CREATE TABLE`, `ALTER TABLE`, ...) +1. Run `prisma2 introspect` to introspect the database and add application models to the Prisma schema +1. Run `prisma2 generate` to update your Prisma Client API + +### Using Prisma Client and Prisma Migrate (experimental) + +> **Warning**: Prisma Migrate is currently in an experimental state. It is ready to be tested and can be used in non-critical projects. However, it is not yet ready for production usage! + +When using Prisma Migrate, you're not using SQL for any operations that change the database schema and you typically don't use Prisma's introspection feature either. Instead, you define your application models manually in the Prisma schema and use the `prisma2 migrate` subcommand to change the schema of the your database. + +Here is an overview of the main workflow: + +1. Manually change your application models in the Prisma schema (e.g. add a new model, remove an existing one, ...) +1. Run `prisma2 migrate save --experimental` to create a migration on the file system +1. Run `prisma2 migrate up --experimental` to apply the migration against your database +1. Run `prisma2 generate` to update your Prisma Client API diff --git a/content/02-understand-prisma/user-table.svg b/content/02-understand-prisma/user-table.svg new file mode 100644 index 0000000000..4e215fb8ef --- /dev/null +++ b/content/02-understand-prisma/user-table.svg @@ -0,0 +1,3 @@ + + +UseridPKfirst_name: stringlast_name: stringemail: stringemail_confirmed: boolbirthDate: date \ No newline at end of file From 491cdd340d10513a4de25f5fc11fbf6c72a6305c Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Fri, 20 Mar 2020 16:08:06 +0100 Subject: [PATCH 03/33] add schema reference --- .../02-understand-prisma/05-data-modeling.mdx | 2 +- .../01-what-is-the-prisma-schema.mdx | 200 +++- .../01-schema/02-data-model.mdx | 5 - .../01-schema/02-data-sources.mdx | 98 ++ .../01-schema/03-connectors.mdx | 5 - .../01-schema/03-generators.mdx | 155 +++ .../01-schema/04-data-model.mdx | 932 ++++++++++++++++++ .../01-schema/04-generators.mdx | 5 - .../01-schema/05-environment-variables.mdx | 5 - .../01-schema/05-models.mdx | 219 ++++ .../01-schema/06-relations.mdx | 663 +++++++++++++ 11 files changed, 2264 insertions(+), 25 deletions(-) delete mode 100644 content/03-reference/01-tools-and-interfaces/01-schema/02-data-model.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx delete mode 100644 content/03-reference/01-tools-and-interfaces/01-schema/03-connectors.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx delete mode 100644 content/03-reference/01-tools-and-interfaces/01-schema/04-generators.mdx delete mode 100644 content/03-reference/01-tools-and-interfaces/01-schema/05-environment-variables.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx diff --git a/content/02-understand-prisma/05-data-modeling.mdx b/content/02-understand-prisma/05-data-modeling.mdx index 75ac2c45bd..6c1ab79dbe 100644 --- a/content/02-understand-prisma/05-data-modeling.mdx +++ b/content/02-understand-prisma/05-data-modeling.mdx @@ -1,5 +1,5 @@ --- - title: "Data modeling with Prisma" + title: "Data modeling" metaTitle: "" metaDescription: "" --- diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx index 88698394ff..46eddf8145 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx @@ -1,5 +1,197 @@ --- - title: "What is the Prisma schema?" - metaTitle: "" - metaDescription: "" ---- \ No newline at end of file +title: "Prisma schema file" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +The Prisma schema file (short: _schema file_, _Prisma schema_ or _schema_) is the main configuration file for your Prisma setup. It is typically called `schema.prisma` and consists of the following parts: + +- [**Data sources**](): Specify the details of the data sources Prisma should connect to (e.g. a PostgreSQL database) +- [**Generators**](): Specifies what clients should be generated based on the data model (e.g. Prisma Client) +- [**Data model definition**](): Specifies your application models (the shape of the data per data source) + +Whenever a `prisma2` command is invoked, the CLI typically reads some information from the schema file, e.g.: + +- `prisma2 generate`: Reads _all_ above mentioned information from the Prisma schema to generate the correct data source client code (e.g. Prisma Client). +- `prisma2 migrate save --experimental`: Reads the data sources and data model definition to create a new migration. + +You can also [use environment variables]() inside the schema file to provide configuration options when a CLI command is invoked. + +## Example + +Here is an example for a Prisma schema file that specifies a data source (SQLite), a generator (Prisma Client) and a data model definition with two models and one enum: + +```prisma +datasource sqlite { + url = "file:./data.db" + provider = "sqlite" +} + +generator client { + provider = "prisma-client-js" +} + +model User { + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) + email String @unique + name String? + role Role @default(USER) + posts Post[] +} + +model Post { + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + title String + author User + published Boolean @default(false) +} + +enum Role { + USER + ADMIN +} +``` + +## Naming + +The default name for the schema file is `schema.prisma`. When your schema file is named like this, the Prisma 2 CLI will detect it automatically in the directory where you invoke the CLI command (or any of its subdirectories). + +If the file is named differently, you can provide the `--schema` argument to the Prisma 2 CLI with the path to the schema file, e.g.: + +``` +prisma2 generate --schema ./database/myschema.prisma +``` + +## Syntax + +The schema file is written in Prisma Schema Language (PSL). You can find a full reference for PSL in the [spec](https://github.com/prisma/specs/tree/master/schema). + +### VS Code + +Syntax highlighting for PSL is available via a [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) (which also lets you auto-format the contents of your Prisma schema and indicates syntax errors with red squiggly lines). Learn more about [setting up Prisma in your editor](). + +### GitHub + +PSL code snippets on GitHub can be rendered with syntax highlighting as well by using the `.prisma` file extension or annotating fenced code blocks in Markdown with `prisma`: + +~~~ +```prisma +model User { + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) + email String @unique + name String? +} +``` +~~~ + +## Using environment variables + +You can use environment variables to provide configuration options when a CLI command is invoked. This can e.g. be helpful in order to: + +- Keep secrets out of the schema file +- Improve portability of the schema file + +### Defining environment variables with the env function + +Environment variables can be accessed using the `env` function: + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} +``` + +There are a few limitations with `env` at the moment: + +- It is not possible to use string concat operations (e.g. to construct your database connection string). +- It is not possible to use environment variables for the `provider` argument in `datasource` and `generator` definitions. + +### Using .env files + +For many developer tools, it has become a good practice to define environment variables using [`.env`](https://github.com/motdotla/dotenv) files. + +Prisma provides native support for `.env` files **if the `.env` file is located in the same directory as your Prisma schema file**: + +``` +. +└── prisma + ├── .env + └── schema.prisma +``` + +This means any environment variables defined in that `.env` file will automatically be loaded when running a Prisma CLI command. + +> **WARNING**: Do not commit your `.env` files into version control. + +For example, it is a common scenario to set your database connection URL via an environment variable: + +```prisma +// schema.prisma +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} +``` + +This requires the `DATABASE_URL` to be set in your `.env` file: + +``` +# .env +DATABASE_URL=postgresql://test:test@localhost:5432/test?schema=public +``` + +When running any command that needs to access the database defined via the `datasource` block (e.g. `prisma2 introspect`), the Prisma CLI automatically loads the `DATABASE_URL` environment variables from the `.env` file and makes it available to the CLI. + +If you want environment variables to be evaluated at runtime, you need to load them manually in your application code, e.g. using [`dotenv`](https://github.com/motdotla/dotenv): + +```ts +import * as dotenv from 'dotenv' + +dotenv.config() // load the environment variables +console.log(`The connection URL is ${process.env.DATABASE_URL}`) +``` + +## Comments + +There are two types of comments that are supported in the schema file: + +- `// comment`: This comment is for the reader's clarity and is not present in the abstract syntax tree (AST) of the schema file. +- `/// comment`: These comments will show up in the abstract syntax tree (AST) of the schema file, either as descriptions to AST nodes or as free-floating comments. Tools can then use these comments to provide additional information. + +Here are some different examples: + +```prisma +/// This comment will get attached to the `User` node in the AST +model User { + /// This comment will get attached to the `id` node in the AST + id Int @default(autoincrement()) + // This comment is just for you + weight Float /// This comment gets attached to the `weight` node +} + +// This comment is just for you. It will not +// show up in the AST. + +/// This is a free-floating comment that will show up +/// in the AST as a `Comment` node, but is not attached +/// to any other node. We can use these for documentation +/// in the same way that godoc.org works. + +model Customer {} +``` + +## Auto formatting + +Similar to tools like [gofmt](https://golang.org/cmd/gofmt/) and [prettier](https://github.com/prettier/prettier), PSL syntax ships with a formatter for +`.prisma` files. The formatter can be enabled in the [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma). + +Like `gofmt` and unlike `prettier`, there are no options for configuration here. **There is exactly one way to format a prisma file**. + +Learn more about the formatting rules in the [spec](https://github.com/prisma/specs/tree/master/schema#formatting-rules). \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/02-data-model.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/02-data-model.mdx deleted file mode 100644 index 2796254cac..0000000000 --- a/content/03-reference/01-tools-and-interfaces/01-schema/02-data-model.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- - title: "Data model" - metaTitle: "" - metaDescription: "" ---- \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx new file mode 100644 index 0000000000..c485b17a47 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx @@ -0,0 +1,98 @@ +--- +title: 'Connectors' +metaTitle: '' +metaDescription: '' +--- + +## Overview + +A data source can be specified using a `datasource` block in the Prisma schema file. + +## Fields + +A `datasource` block accepts the following fields: + +| Name | Required | Type | Description | +| ---------- | -------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| `provider` | **Yes** | Enum (`postgresql`, `mysql`, `sqlite`) | Describes which data source connector to use. | +| `url` | **Yes** | String (URL) | Connection URL including authentication info. Most connectors use the syntax provided by the database, [learn more](). | + +## Examples + +**Specify a PostgreSQL data source** + +In this example, the target database is available with the following credentials: + +- User: `johndoe` +- Password: `mypassword` +- Host: `localhost` +- Post: `5432` +- Database name: `mydb` +- Schema name: `public` + +```prisma +datasource postgresql { + provider = "postgresql" + url = "postgresql://johndoe:mypassword@localhost:5432/mydb?schema=public" +} +``` + +Learn more about PostgreSQL connection strings [here](). + +**Specify a MySQL data source** + +In this example, the target database is available with the following credentials: + +- User: `johndoe` +- Password: `mypassword` +- Host: `localhost` +- Post: `5432` +- Database name: `mydb` + +```prisma +datasource mysql { + provider = "mysql" + url = "mysql://johndoe:mypassword@localhost:5432/mydb" +} +``` + +Learn more about PostgreSQL connection strings [here](). + +**Specify a SQLite data source** + +In this example, the target database is located in a file called `dev.db`: + +```prisma +datasource sqlite { + provider = "sqlite" + url = "file:./dev.db" +} +``` + +Learn more about SQLite connection strings [here](). + +**Specify a PostgreSQL data source via an environment variable** + +In this example, the target database is available with the following credentials: + +- User: `johndoe` +- Password: `mypassword` +- Host: `localhost` +- Post: `5432` +- Database name: `mydb` +- Schema name: `public` + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} +``` + +When running a Prisma CLI command that needs the database connection URL (e.g. `prisma generate`), you need to make sure that the `DATABASE_URL` environment variable is set. + +One way to do so is by creating a [`.env`](https://github.com/motdotla/dotenv) file with the following contents. Note that the file must be in the same directory as your `schema.prisma` file to automatically picked up the Prisma CLI. + +``` +DATABASE_URL=postgresql://johndoe:mypassword@localhost:5432/mydb?schema=public +``` diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/03-connectors.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/03-connectors.mdx deleted file mode 100644 index c21c60fdf7..0000000000 --- a/content/03-reference/01-tools-and-interfaces/01-schema/03-connectors.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- - title: "Connectors" - metaTitle: "" - metaDescription: "" ---- \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx new file mode 100644 index 0000000000..f6c4410596 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx @@ -0,0 +1,155 @@ +--- +title: "Generators" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +A generator can be specified via the `generator` block in the Prisma schema. + +## Fields + +A `generator` block accepts the following fields: + +| Name | Required | Type | Description | +| --------------- | -------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `provider` | **Yes** | String (file path) or Enum (`prisma-client-js`) | Describes which generator to use. This can point to a file that implements a generator or specify a built-in generator directly. | +| `output` | No | String (file path) | Determines the location for the generated client, [learn more](). **Default**: `node_modules/@prisma/client` | +| `binaryTargets` | No | List of Enums (see below0) | Specify the OS on which the Prisma Client will run to ensure binary compatibility of the [query engine](). **Default**: `native` | + +## Binary targets + +Prisma relies on several [engine binaries](https://github.com/prisma/prisma-engines). For example, Prisma Client uses the [query engine binary file]() under the hood to communicate with a database. Prisma Migrate uses the [migration engine binary file]() to run schema migrations against a database. + +These _engines_ are implemented in Rust and are used by Prisma in the form of executable _binary files_. + +Being aware of the binary file is especially important when [deploying]() your application to production! + +> **Note**: You can learn more about binary targets in the [spec](https://github.com/prisma/specs/blob/master/binaries/Readme.md). + +### Supported operating systems + +The following tables list all supported operating systems with the name of the binary file to specify in `binaryTargets`. + +#### Mac OS + +| Build OS | Build name | +| :------- | :--------- | +| Mac OS | `darwin` | + +#### Windows + +| Build OS | Build name | +| :------- | :--------- | +| Windows | `windows` | + +#### Linux (Debian) + +| Build OS | Build name | OpenSSL | +| :----------------- | :--------------------- | :-----: | +| Debian 8 (Jessie) | `debian-openssl-1.0.x` | 1.0.x | +| Debian 9 (Stretch) | `debian-openssl-1.1.x` | 1.1.x | +| Debian 10 (Jessie) | `debian-openssl-1.1.x` | 1.1.x | + +#### Linux (Ubuntu) + +| Build OS | Build name | Build OS | OpenSSL | +| :-------------------- | :--------------------- | :------: | ------- | +| Ubuntu 14.04 (trusty) | `debian-openssl-1.0.x` | 1.0.x | +| Ubuntu 16.04 (xenial) | `debian-openssl-1.0.x` | 1.0.x | +| Ubuntu 18.04 (bionic) | `debian-openssl-1.1.x` | 1.1.x | +| Ubuntu 19.04 (disco) | `debian-openssl-1.1.x` | 1.1.x | + +#### Linux (CentOS) + +| Build OS | Build name | OpenSSL | +| :------- | :------------------- | :-----: | +| CentOS 6 | `rhel-openssl-1.0.x` | 1.0.x | +| CentOS 7 | `rhel-openssl-1.0.x` | 1.0.x | + +#### Linux (Fedora) + +| Build OS | Build name | OpenSSL | +| :-------- | :------------------- | :-----: | +| Fedora 28 | `rhel-openssl-1.1.x` | 1.1.x | +| Fedora 29 | `rhel-openssl-1.1.x` | 1.1.x | +| Fedora 30 | `rhel-openssl-1.1.x` | 1.1.x | + +#### Linux (Linux Mint) + +| Build OS | Build name | OpenSSL | +| :------------ | :--------------------- | :-----: | +| Linux Mint 18 | `debian-openssl-1.0.x` | 1.0.x | +| Linux Mint 19 | `debian-openssl-1.1.x` | 1.1.x | + +#### Linux (Arch Linux) + +| Build OS | Build name | OpenSSL | +| :-------------------- | :--------------------- | :-----: | +| Arch Linux 2019.09.01 | `debian-openssl-1.1.x` | 1.1.x | + +#### The native binary target + +The `native` binary target is special. It doesn't map to a concrete operating system. Instead, when `native` is specified in `binaryTargets`, Prisma detects the _current_ operating system and automatically specifies the correct binary target for it. + +As an example, assume you're running **Mac OS** and you specify the following generator: + +```prisma +generator client { + provider = "prisma-client-js" + binaryTargets = ["native"] +} +``` + +In that case, Prisma detects your operating system and finds the right binary file for it based on the table [above](#supported-operating-systems). As you're running Mac OS, the binary file that was compiled for `darwin` will be selected. + +## Examples + +**Specify the `prisma-client-js` generator with the default `output` and `binaryTargets`** + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Note that the above `generator` definition is **equivalent** to the following because it uses the default values for `output` and `binaryTargets`: + +```prisma +generator client { + provider = "prisma-client-js" + output = "node_modules/@prisma/client" + binaryTargets = ["native"] +} +``` + +**Specify a custom `output` location for Prisma Client** + +```prisma +generator client { + provider = "prisma-client-js" + output = "../src/generated/client" +} +``` + +**Specify custom `binaryTargets` to ensure compatibility with the OS** + +This example shows how to configure Prisma Client to run on `Ubuntu 19.04 (disco)` based on the table [above](#linux-ubuntu). + +```prisma +generator client { + provider = "prisma-client-js" + binaryTargets = ["debian-openssl-1.1.x"] +} +``` + +**Specify a `provider` pointing to some custom generator implementation** + +This example shows how to use a custom generator that's located in a directory called `my-generator`. + +```prisma +generator client { + provider = "./my-generator" +} +``` \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx new file mode 100644 index 0000000000..704ec10d8e --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx @@ -0,0 +1,932 @@ +--- + title: "Data model" + metaTitle: "" + metaDescription: "" +--- + +## Overview + +The data model definition defines your _application models_ (also called _Prisma models_). These models represent the _entities of your application domain_ and map to the _tables_ in your database. + +Models are the foundation for all available queries in the [Prisma Client API](). When used with TypeScript, Prisma Client provides generated type definitions for your models and any [variations]() of them to make database access entirely type safe. + +### Application domain examples + +A few examples are for application domains and "typical" models are: + +- In a **blogging** application you probably have models like `Blog`, `Author`, `Article` and `Comment`. +- In an **e-commerce** application you probably have models like `Customer`, `Order`, `Item` and `Invoice`. +- In a **social media** application you probably have models like `User`, `Post`, `Photo` and `Message`. + +### Technical purpose of Prisma models + +On a _technical_ level, these models serve two main purposes: + +- They represent the tables in the underlying database. +- They are the foundation for the available queries in the generated [Prisma Client API](). + +### Data modeling primitives + +You can create your data model using the following primitives: + +- `model`: Defines a [Prisma model]() +- `enum`: Defines an [enum]() (only available if enums are supported natively by your database) + +Additionally, you can configure your models with [attributes]() and [functions](). + +## Example + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + +model User { + id Int @id @default(autoincrement()) + email String @unique + name String? + role Role @default(USER) + posts Post[] + profile Profile? +} + +model Profile { + id Int @id @default(autoincrement()) + user User + bio String +} + +model Post { + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) + author User + title String + published Boolean @default(false) + categories Category[] +} + +model Category { + id Int @id @default(autoincrement()) + name String + posts Post[] +} + +enum Role { + USER + ADMIN +} +``` + +## Introspection vs Prisma Migrate + +Depending on the use case, the data model is typically created in either of two ways: + +- **Manually written**: You can write your data model manually and map it to your database using [Prisma Migrate]() (experimental). In this case, the data model is the single source of truth for the models your application. +- **Generated from introspection**: When you have an existing database or prefer migrating your database schema with SQL, you generate the data model by [introspecting]() your database. In this case, the database schema is the single source of truth for the models your application. + +> **Note**: Since Prisma Migrate is currently in an experimental state, the officially recommended way for using Prisma is the introspection-based approach. + +## Models + +You can find information about models [here](). + +## Scalar types + +You can use the following scalar types in the Prisma data model: + +| Prisma Type | Description | +| ----------- | --------------------- | +| `String` | Variable length text | +| `Boolean` | True or false value | +| `Int` | Integer value | +| `Float` | Floating point number | +| `DateTime` | Timestamp | + +The _data source connector_ determines what _native database type_ each of these types map to. Similarly, the _generator_ determines what _type in the target programming language_ each of these types map to. + +Expand below to see the mappings per connector and generator. + +
Scalar mapping to connectors and generators +
+ +**Connectors** + +| Type | PostgreSQL | MySQL | SQLite | Raw JSON | +| ---------- | ----------- | ----------- | --------- | --------- | +| `String` | `text` | `TEXT` | `TEXT` | `string` | +| `Boolean` | `boolean` | `BOOLEAN` | n/a | `boolean` | +| `Int` | `integer` | `INT` | `INTEGER` | `number` | +| `Float` | `real` | `FLOAT` | `REAL` | `number` | +| `DateTime` | `timestamp` | `TIMESTAMP` | n/a | n/a | + +**Generators** + +| Type | Prisma Client JS | +| ---------- | ---------------- | +| `String` | `string` | +| `Boolean` | `boolean` | +| `Int` | `number` | +| `Float` | `number` | +| `DateTime` | `Date` | + +
+ +## Enums + +You can define enums in your data model if they're supported by the [data source]() you use: + +- PostgreSQL: [Supported](https://www.postgresql.org/docs/9.1/datatype-enum.html) +- MySQL: [Supported](https://dev.mysql.com/doc/refman/8.0/en/enum.html) +- SQLite: Not supported + +Enums are considered [scalar](#scalar-types) types in the Prisma data model. They're therefore [by default]() included as return values in [Prisma Client API]() calls. + +Enums are defined via the `enum` block. + +### Examples + +**Specify an `enum` with two possible values** + +```prisma +enum Role { + USER + ADMIN +} + +model User { + id Int @id @default(autoincrement()) + role Role +} +``` + +**Specify an `enum` with two possible values and set a default value** + +```prisma +enum Role { + USER + ADMIN +} + +model User { + id Int @id @default(autoincrement()) + role Role @default(USER) +} +``` + +## Attributes + +Attributes modify the behavior of a [field](#fields) or block (e.g. [models](#models)). There are two ways to add attributes to your data model: + +- _Field_ attributes are prefixed with `@` +- _Block_ attributes are prefixed with `@@` + +### Overview + +Here's a quick overview of the available field attributes: + +| Name | Database representation | Arguments | Description | +| :---------- | :--------------------------- | :---------------------------------------- | :------------------------------------------------------------------------------------- | +| `@id` | `PRIMARY KEY` | - | Defines a single-field ID on the model. | +| `@@id` | `PRIMARY KEY` | A list of field references | Defines a multi-field ID on the model. | +| `@default` | `DEFAULT` | An expression (e.g. `5`, `true`, `now()`) | Defines a default value for this field. `@default` takes an expression as an argument. | +| `@unique` | `UNIQUE` | - | Defines a unique constraint for this field. | +| `@@unique` | `UNIQUE` | A list of field references | Defines a unique constraint for the specified fields. | +| `@@index` | `INDEX` | A list of field references | Defines an index. | +| `@relation` | `FOREIGN KEY` / `REFERENCES` | A name and/or a list of field references | Defines meta information about the relation. [Learn more](). | +| `@map` | n/a | The name of the target database column | Maps a field name from the Prisma schema to a different column name. | +| `@@map` | n/a | The name of the target database table | Maps a model name from the Prisma schema to a differenttable name. | + +Here's an overview of the extact signatures of all attributes: + +``` +// IDs +@id +@@id(_ fields: FieldReference[]) + +// Unique +@unique +@@unique(_ fields: FieldReference[]) + +// Default +@default(_ expression: Expression) + +// Index +@@index(_ fields: FieldReference[]) + +// Mapping model/field names from Prisma schema to database +@map(_ name: String) +@@map(_ name: String) + +// Configuring relations +@relation(_ name: String?, references: FieldReference[]?) +``` + +The leading underscore in a signature means the _argument name_ can be omitted (read more [below](#arguments)). + +| Type | Description | Example | +| :----------------- | :--------------------------------------- | :------------------------------------- | +| `FieldReference[]` | An array of [field](#fields) names | `[id]`, `[firstName, lastName]` | +| `String` | A variable length text in `""` | `""`, `"Hello World"`, `"Alice"` | +| `Expression` | An expression can be evaluated by Prisma | `42.0`, `""`, `Bob`, `now()`, `cuid()` | + +### Arguments + +Note that some attributes take arguments. Arguments in attributes are always named, but in most cases the argument _name_ can be ommitted. + +The following pairs of default values are all equivalent: + +The name of the `fields` argument on the `@@id` attribute can be omitted: + +```prisma +@@id(fields: [title, author]) +@@id([title, author]) +``` + +The name of the `value` argument on the `@default` attribute can be omitted: + +```prisma +id Int @id @default(value: autoincrement()) +id Int @id @default(autoincrement()) +``` + +The name of the `fields` argument on the `@@unique` attribute can be omitted: + +```prisma +@@unique(fields: [title, author]) +@@unique([title, author]) +``` + +The name of the `fields` argument on the `@@index` attribute can be omitted: + +```prisma +@@index(fields: [title, author]) +@@index([title, author]) +``` + +The name of the `name` argument on the `@relation` attribute can be omitted (`references` is required though): + +```prisma +@relation(name: "UserOnPost", references: [id]) +@relation("UserOnPost", references: [id]) + +// or + +@relation(name: "UserOnPost") +@relation("UserOnPost") +``` + +The name of the `name` argument on the `@map` and `@@map` attributes can be omitted: + +```prisma +@map(name: "is_admin") +@map("is_admin") + +// and + +@@map(name: "users") +@@map("users") +``` + +### IDs + +You can add IDs to your models to be able to uniquely identify individual records of that model. In relational databases, this ID corresponds to a `PRIMARY KEY` constraint. + +IDs can be defined on a **single field** using `@id` or on **multiple fields** (also called composite or compound IDs) using `@@id`. Any model can at most have one ID, no matter if it's defined on a single field or on multiple fields. + +#### Signature + +The signatures of the `@id` attribute looks as follows: + +``` +@id +``` + +The signatures of the `@@id` attribute looks as follows: + +``` +@@id(_ fields: FieldReference[]) +``` + +#### Single-field IDs + +To determine which field of a model represents the ID, you can annotate it with the `@id` attribute. Note that a field that's annotated with `@id` can not be [optional](#optional-vs-required). + +`@id` attributes can be defined on fields of any [type](#field-types) in your Prisma schema (e.g. `Int`, `String`, enums, relation fields, ...). The only exception are [virtual back-relation fields](). + +##### Single-field IDs without default values + +```prisma +model User { + id String @id + name String +} +``` + +Note that in the above case, you _must_ provide your own ID values when creating new records for the `User` model using Prisma Client, e.g.: + +```ts +const newUser = await prisma.user.create({ + data: { + id: 1, + name: 'Alice', + }, +}) +``` + +##### Single-field IDs with default values + +In most cases, you want to have the ID initialized by your database. To do so, you can annotate it with the `@default` attribute and initialize the field with a [function](). + +These are the available functions and the types they're compatible with: + +| Function | Type | Description | +| :---------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `autoincrement()` | `Int` | Create a sequence of integers in the underlying database and assign the incremented values to the ID values of the created records based on the sequence. | +| `cuid()` | `String` | Generate a globally unique identifier based on the [`cuid`](https://github.com/ericelliott/cuid) spec. Only available when using [Prisma Migrate](). | +| `uuid()` | `String` | Generate a globally unique identifier based on the [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) spec. Only available when using [Prisma Migrate](). | + +Note that using these functions will have different effects with respect to your database and Prisma internals: + +| Function | PostgreSQL | MySQL | SQLite | Prisma | +| :---------------- | :-------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------- | :------------------------------ | +| `cuid()` | n/a | n/a | n/a | Implemented by [query engine]() | +| `uuid()` | n/a | n/a | n/a | Implemented by [query engine]() | +| `autoincrement()` | Uses the [`SERIAL`](https://www.postgresql.org/docs/9.1/datatype-numeric.html#DATATYPE-SERIAL) type | Uses the [`AUTO_INCREMENT`](https://dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html) attribute | Uses the [`AUTOINCREMENT`](https://www.sqlite.org/autoinc.html) keyword | n/a | + +This table shows how each of these functions is implemented. + +`cuid()` and `uuid()` are implemented by Prisma and therefore are not "visible" in the underlying database schema. This means you can only use those features when running schema migrations with [Prisma Migrate]() but _not_ when using [introspection](). + +`autoincrement()` on the other hand is always "implememented" on the database-level, meaning it's visible in the database schema and can be recognized through introspection. + +##### Examples + +**Specify an ID on `String` without a default value** + +```prisma +model User { + id String @id + name String +} +``` + +**Specify an ID on sign field `author` without a default value** + +```prisma +model Post { + author User @id + title String + published Boolean @default(false) +} + +model User { + email String @unique + name String? + posts Post[] +} +``` + +Note that in this case you can only create new `Post` records by using Prisma Client's [nested writes]() to immediately connect the new `Post` record with a new or existing `User` record, e.g.: + +```ts +const post = await prisma.post.create({ + data: { + title: 'Hello World', + author: { + create: { + name: 'Alice', + email: 'alice@prisma.io', + }, + }, + }, +}) +``` + +Or when a `User` record with `bob@prisma.io` as its `email` already exists, you can connect it to the new `Post` record in a nested write: + +```ts +const post = await prisma.post.create({ + data: { + title: 'Hello World', + author: { + connect: { + email: 'bob@prisma.io', + }, + }, + }, +}) +``` + +**Generate `cuid()` values as IDs** + +```prisma +model User { + id String @id @default(cuid()) + name String +} +``` + +**Generate `uuid()` values as IDs** + +```prisma +model User { + id String @id @default(uuid()) + name String +} +``` + +**Generate auto-incrementing integers as IDs** + +```prisma +model User { + id Int @id @default(autoincrement()) + name String +} +``` + +#### Multi-field IDs + +To determine which fields of a model represent the multi-field ID, you can include them in the `@@id` attribute that's defined on your model. + +`@@id` attributes can include fields of any [type](#field-types) in your Prisma schema (e.g. `Int`, `String`, enums, relation fields, ...). + +##### Examples + +**Specify a multi-field ID on two `String` fields** + +```prisma +model User { + firstName String + lastName String + email String @unique + isAdmin Boolean @default(false) + + @@id([firstName, lastName]) +} +``` + +When creating new `User` records, you now must provide a unique combination of values for `firstName` and `lastName`: + +```ts +const user = await prisma.user.create({ + data: { + firstName: 'Alice', + lastName: 'Smith', + }, +}) +``` + +**Specify a multi-field ID on two `String` fields and one `Boolean` field** + +```prisma +model User { + firstName String + lastName String + email String @unique + isAdmin Boolean @default(false) + + @@id([firstName, lastName, isAdmin]) +} +``` + +When creating new `User` records, you now must provide a unique combination of values for `firstName`, `lastName` and `isAdmin`: + +```ts +const user = await prisma.user.create({ + data: { + firstName: 'Alice', + lastName: 'Smith', + isAdmin: true, + }, +}) +``` + +**Specify a multi-field ID that includes a relation field** + +```prisma +model Post { + author User + title String + published Boolean @default(false) + + @@id([author, title]) +} + +model User { + id Int @default(autoincrement()) + email String @unique + name String? + posts Post[] +} +``` + +When creating new `Post` records, you now must provide a unique combination of values for `author` (foreign key) and `title`: + +```ts +const post = await prisma.post.create({ + data: { + title: 'Hello World', + author: { + connect: { + email: 'alice@prisma.io', + }, + }, + }, +}) +``` + +### Unique + +You can add unique attributes to your models to be able to uniquely identify individual records of that model. In relational databases, this corresponds to adding a `UNIQUE` constraint. + +Unique attributes can be defined on a **single field** using `@unique` or on **multiple fields** (also called composite or compound IDs) using `@@unique`. A model can have any number of unique attributes. + +> **Note**: Adding a unique constraint automatically adds a corresponding _unique index_ to the specified column(s). + +#### Signature + +The signatures of the `@unique` attribute looks as follows: + +``` +@unique +``` + +The signatures of the `@@unique` attribute looks as follows: + +``` +@@unique(_ fields: FieldReference[]) +``` + +#### Single-field unique attributes + +To add a unique attribute to a field of a model, you can annotate it with the `@unique` attribute. A field that's annotated with `@unique` can be [optional or required](#optional-vs-required). If the field is optional, `null` values are always considered to be distinct from each other and any other values. + +The only exception where a field annotated with `@unique` _must_ be required is when it is the only unique constraint on a model that has no ID: + +```prisma +model User { + email String @unique // `email` can not be optional because it's the only unique field on the model + name String? +} +``` + +`@unique` attributes can be defined on fields of any [type](#field-types) in your Prisma schema (e.g. `Int`, `String`, enums, relation fields, ...). The only exception are [virtual back-relation fields](). + +##### Examples + +**Specify a unique attribute on a required `String` field** + +```prisma +model User { + email String @unique + name String +} +``` + +**Specify a unique attribute on an optional `String` field** + +```prisma +model User { + id Int @id @default(autoincrement()) + email String? @unique + name String +} +``` + +Note that in this case, it is _allowed_ to have multiple `User` records in the database where the `email` is `NULL` because `NULL` values are considered to distinct from each other. + +**Specify a unique attribute on relation field `author`** + +```prisma +model Post { + author User @unique + title String + published Boolean @default(false) +} + +model User { + email String @unique + name String? + posts Post[] +} +``` + +**Specify a unique attribute with `cuid()` values as default values** + +```prisma +model User { + id String @unique @default(cuid()) + name String +} +``` + +#### Multi-field unique attributes + +To add multi-field unique attribue to a model, you have to annotate it with the `@@unique` attribute and provide the list of referenced fields as an argument. + +`@@unique` attributes can include fields of any [type](#field-types) in your Prisma schema (e.g. `Int`, `String`, enums, relation fields, ...). + +##### Examples + +**Specify a multi-field unique attribute on two `String` fields** + +```prisma +model User { + id Int @default(autoincrement()) + firstName String + lastName String + isAdmin Boolean @default(false) + + @@unique([firstName, lastName]) +} +``` + +**Specify a multi-field unique attribute on two `String` fields and one `Boolean` field** + +```prisma +model User { + id Int @default(autoincrement()) + firstName String + lastName String + isAdmin Boolean @default(false) + + @@unique([firstName, lastName, isAdmin]) +} +``` + +**Specify a multi-field unique attribute that includes a relation field** + +```prisma +model Post { + id Int @default(autoincrement()) + author User + title String + published Boolean @default(false) + + @@unique([author, title]) +} + +model User { + id Int @default(autoincrement()) + email String @unique + posts Post[] +} +``` + +### Default values + +You can define default values for the fields of your models using the `@default` attribute. `@default` attributes are typically represented by `DEFAULT` values in the underlying database (with a few exceptions like `cuid()` and `uuid()` which are provided by Prisma's [query engine]() and are therefore not "visible" in the underlying database schema). + +The `@default` attribute takes as argument an _expression_, this can be a static, hardcoded value e.g. `5`, `true`, `"Hello"` or a function, e.g. `now()`, `uuid()`, `cuid()`. Note that there is a special function in the Prisma schema called `dbgenerated()` which is used in [introspection]() results for default values that can not yet be represented in the Prisma schema. + +Default values can be defined on any scalar type but not on relation fields. + +#### Signature + +The signatures of the `@default` attribute looks as follows: + +``` +@default(_ expression: Expression) +``` + +#### Static default values + +For [scalar types](), you can use any static value that corresponds to the type of a field as a default value: + +| Type | Examples | +| :--------- | :------------------------------- | +| `Int` | `-100`, `0`, `42` | +| `Float` | `-100.5`, `0`, `4.2` | +| `String` | `"Alice"`, `"Hello World"`, `""` | +| `Boolean` | `true`, `false` | +| `DateTime` | `"2020-03-19T14:21:00+0200"` | + +Note that static default values for `DateTime` are based on the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard. However, they must always include the time including the [time offsets from UTC](https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC). + +Similarly, you can define default values for [enums](#enums). Assume you have the following enum definition: + +```prisma +enum Role { + USER + ADMIN +} +``` + +In that case, you have two possible values as default values: + +| Type | Examples | +| :----- | :------------------ | +| `Role` | `ADMIN`, `CUSTOMER` | + +#### Functions as default values + +These are the available functions and the types they're compatible with: + +| Function | Type | Description | +| :---------------- | :--------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `autoincrement()` | `Int` | Create a sequence of integers in the underlying database and assign the incremented values to the ID values of the created records based on the sequence. | +| `now()` | `DateTime` | Set a timestamp of the time when a record is created. | +| `cuid()` | `String` | Generate a globally unique identifier based on the [`cuid`](https://github.com/ericelliott/cuid) spec. Only available when using [Prisma Migrate](). | +| `uuid()` | `String` | Generate a globally unique identifier based on the [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) spec. Only available when using [Prisma Migrate](). | +| `dbgenerated()` | Any | Represents default values that can't be expressed in the Prisma schema. Only available after [introspection](). | + +Note that using these functions will have different effects with respect to your database and Prisma internals: + +| Function | PostgreSQL | MySQL | SQLite | Prisma | +| :---------------- | :----------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------- | :------------------------------ | +| `cuid()` | n/a | n/a | n/a | Implemented by [query engine]() | +| `uuid()` | n/a | n/a | n/a | Implemented by [query engine]() | +| `autoincrement()` | Uses the [`SERIAL`](https://www.postgresql.org/docs/9.1/datatype-numeric.html#DATATYPE-SERIAL) type | Uses the [`AUTO_INCREMENT`](https://dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html) attribute | Uses the [`AUTOINCREMENT`](https://www.sqlite.org/autoinc.html) keyword | n/a | +| `now()` | [`CURRENT_TIMESTAMP`](https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT) and aliases like `now()` | [`CURRENT_TIMESTAMP`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_current-timestamp) and aliases like `now()` | [`CURRENT_TIMESTAMP`]() and aliases like `date('now')` | +| `dbgenerated()` | Any expression | Any expression | Any expression | n/a | + +This table shows how each of these functions is implemented. + +`cuid()` and `uuid()` are implemented by Prisma and therefore are not "visible" in the underlying database schema. This means you can only use those features when running schema migrations with [Prisma Migrate]() but _not_ when using [introspection](). + +`autoincrement()`, `now` and `dbgenerated()` on the other hand are always "implememented" on the database-level, meaning they're visible in the database schema and can be recognized through introspection. + +#### Examples + +**Default value for an `Int`** + +```prisma +model User { + email String @unique + profileViews Int @default(0) +} +``` + +**Default value for a `Float`** + +```prisma +model User { + email String @unique + number Float @default(1.1) +} +``` + +**Default value for a `String`** + +```prisma +model User { + email String @unique + name String @default("") +} +``` + +**Default value for a `Boolean`** + +```prisma +model User { + email String @unique + isAdmin Int @default(false) +} +``` + +**Default value for a `DateTime`** + +Note that static default values for `DateTime` are based on the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard. However, they must always include the time including the [time offsets from UTC](https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC). + +```prisma +model User { + email String @unique + data DateTime @default("2020-03-19T14:21:00+0200") +} +``` + +#### Limitations + +Default values are currently not allowed on relation fields in the Prisma schema. Note however that you can still define default values _manually_ in the underlying database using plain SQL. These will not be represented in the Prisma schema though, this is a temporary limitation which you can [track on GitHub](https://github.com/prisma/prisma2/issues/1111). + +### Indexes + +You can define indexes on one or multiple fields of your models via the `@@index` on a model. + +#### Signature + +The signature of the `@@index` attribute looks as follows: + +``` +@@index(_ fields: FieldReference[]) +``` + +#### Examples + +Assume you want to add an index for the `title` field of the `Post` model from the example [above](#example). You can define the index like so: + +```prisma +model Post { + id Int @id @default(autoincrement()) + title String + content String? + + @@index([title]) +} +``` + +To define an index on multiple fields (i.e. a multi-column index), you can add more fields to the array passed to the `@@index` attribute, e.g.: + +```prisma +model Post { + id Int @id @default(autoincrement()) + title String + content String? + + @@index([title, content]) +} +``` + +#### Limitations + +It is currently not possible to provide more configuration options to the index: + +- PostgreSQL + - Define index fields as expressions (e.g. `CREATE INDEX title ON public."Post"((lower(title)) text_ops);`) + - Specify index methods with `USING`; PostgreSQL supports these index methods: B-tree, hash, GiST, and GIN; Prisma uses B-Tree by default + - Define partial indexes with `WHERE` + - Create indexes concurrently with `CONCURRENTLY` +- MySQL + - Specify index methods with `USING`; MySQL supports these index methods: B-tree, hash; Prisma uses B-Tree by default + +### Mapping column and table names + +You can use the `@map` and `@@map` attributes to map field and model names in your Prisma schema to different column and table names in the underlying database schema. + +Read more about this on the [Configuring the Prisma Client API]() page. + +#### Signature + +The signature of the `@map` attribute looks as follows: + +``` +@map(_ name: String) +``` + +The signature of the `@@map` attribute looks as follows: + +``` +@@map(_ name: String) +``` + +#### Examples + +**Map the `User` model to a table called `users`**: + +```prisma +model User { + id Int @default(autoincrement()) + name String + + @@map("users") +} +``` + +**Map the `firstName` field to a column called `first_name`**: + +```prisma +model User { + id Int @default(autoincrement()) + firstName String @map("first_name") +} +``` + +**Map the `User` model to a table called `users` and `firstName` field to a column called `first_name`**: + +```prisma +model User { + id Int @default(autoincrement()) + firstName String @map("first_name") + + @@map("users") +} +``` + +### Configuring relations + +The `@relation` attribute lets you specify meta-information about a relation. In most cases the `@relation` attribute is optional, but sometimes it can be required (e.g. to disambiguate two relations between the same models). + +#### Signature + +The signature of the `@relation` attribute looks as follows: + +``` +@relation(_ name: String?, references: FieldReference[]?) +``` + +#### Examples + +**Disambiguate two relations between `User` and `Post`**: + +```prisma + +``` + +## Functions + +The Prisma schema supports a number of functions. These can be used to specify [default values](#default-values) on fields of a model. You can find a reference for all available functions [here](#functions-as-default-values). diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/04-generators.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/04-generators.mdx deleted file mode 100644 index a0141c644b..0000000000 --- a/content/03-reference/01-tools-and-interfaces/01-schema/04-generators.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- - title: "Generators" - metaTitle: "" - metaDescription: "" ---- \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/05-environment-variables.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/05-environment-variables.mdx deleted file mode 100644 index ec3e730383..0000000000 --- a/content/03-reference/01-tools-and-interfaces/01-schema/05-environment-variables.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- - title: "Env variables" - metaTitle: "" - metaDescription: "" ---- \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx new file mode 100644 index 0000000000..aea03632fa --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx @@ -0,0 +1,219 @@ +--- + title: "Models" + metaTitle: "" + metaDescription: "" +--- + +## Overview + +This is an extension of the [Data model]() page that discusses _models_ in the data model definition in detail. + +Models represent the entities of your application domain. They are defined using `model` blocks in the data model. In the [example data model](), `User`, `Profile`, `Post` and `Category` are models. Here's the `User` model from the example on the again for reference: + +```prisma +model User { + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) + email String @unique + name String? + role Role @default(USER) + posts Post[] + profile Profile? +} +``` + +On a technical level, a model maps to the underlying structures of the data source, e.g.: + +- In PostgreSQL, a model maps to a _table_ +- In MySQL, a model maps to a _table_ +- In SQLite, a model maps to a _table_ + +> **Note**: In the future there might be connectors for non-relational databases and other data sources. For example, for MongoDB a model would map to a _collection_, for a REST API it would map to a _resource_. + +## Naming models + +Models are typically spelled in [PascalCase](http://wiki.c2.com/?PascalCase) and use the singular form (e.g. `User` instead of `user`, `users` or `Users`). + +Technically, a model can be named anything that adheres to this regular expression: + +``` +[A-Za-z_][A-Za-z0-9_]* +``` + +Note that naming conventions in databases wildly differ. A common approach for naming tables in databases is to use plural form and [snake_case](https://en.wikipedia.org/wiki/Snake_case) notation, e.g. `users`. When introspecting a database where a table is called `users`, you'll end up with a model looking similar to this: + +```prisma +model users { + id Int @id @default(autoincrement()) + first_name String + // more fields ... +} +``` + +In this case, the naming convention of the Prisma schema is broken. However, you can still adhere to the naming convention without renaming the underlying `users` table in the database by using the `@@map` attribute: + +```prisma +model User { + id Int @id @default(autoincrement()) + first_name String + // more fields ... + + @@map(name: "users") +} +``` + +With this model definition, Prisma automatically maps the `User` model to the `users` table in the underlying database. Note that you can also map column names to field names using `@map`: + +```prisma +model User { + id Int @id @default(autoincrement()) + firstName String @map(name: "first_name") + // more fields ... + + @@map(name: "users") +} +``` + +`@@map` and `@map` are often used to [configure your Prisma Client API]() by decoupling it from the naming of tables and columns in the underlying database. + +## Fields + +The properties of a model are called _fields_. Fields map to _columns_ and consist of several parts: + +- [Name](#naming-fields) +- [Type](#types) +- [Type modifier](#type-modifiers) (optional) +- [Attributes](#attributes) (optional) + +Here's an overview of these for the fields from the `User` model [above](#example): + +| Name | Type | Scalar vs Relation | Type modifier | Attributes | +| :---------- | :--------- | :----------------- | :------------ | :------------------------------------ | +| `id` | `Int` | Scalar | - | `@id` and `@default(autoincrement())` | +| `createdAt` | `DateTime` | Scalar | - | `@default(now())` | +| `email` | `String` | Scalar | - | `@unique` | +| `name` | `String` | Scalar | `?` | - | +| `role` | `Role` | Scalar (enum) | - | `@default(USER)` | +| `posts` | `Post` | Relation | `?` | - | +| `profile` | `Profile` | Relation | `[]` | - | + +### Naming fields + +Field names are typically spelled in [camelCase](http://wiki.c2.com/?CamelCase). + +Technically, a field can be named anything that adheres to this regular expression: + +``` +[A-Za-z_][A-Za-z0-9_]* +``` + +> **Note**: There's currently a [bug](https://github.com/prisma/prisma2/issues/259) that doesn't allow for field names prepended with an underscore. The current regular expression for valid field names therefore is: `[A-Za-z][A-Za-z0-9_]*` + +### Field types + +#### Scalar fields vs relation fields + +The type of a field determines its _structure_. A type falls in either of two categories: + +- [Scalar type](#scalar-types) (includes [enums](#enums)) +- [Model](#models) ("relation field") + +Prisma supports the following scalar types: + +- `Int` +- `Float` +- `String` +- `Boolean` +- `DateTime` +- `enum` definitions + +### Type modifiers + +The type of a field can be modified by appending either of two modifiers: + +- `[]`: Make a field a **list** +- `?`: Make a field **optional** + +In the main example above, the field `name` on the `User` model is _optional_ and the `posts` relation field is a _list_. + +Note that you can not combine the list and optional modifiers on the same field. So, the following would be illegal in Prisma: + +```prisma +model User { + id Int @id @default(autincremenent()) + posts Post[]? // 🚨🚓 +} +``` + +#### Lists + +When annotated with the `[]` type modifier, a field becomes a list. This means it can hold multiple elements of the specified type. + +> **Note**: Scalar lists (arrays) are only supported in the data model if your database natively supports them. Currently, scalar lists are therefore only supported when using PostgreSQL (since MySQL and SQLite don't natively support scalar lists). + +#### Optional vs required + +When **not** annotating a field with the `?` type modifier, the field will be _required_ on every record of the model. This has effects on two levels: + +- **Database**: Required fields are represented via `NOT NULL` constraintß in the underlying database. +- **Prisma Client**: Prisma Client's generated [TypeScript types](#type-definitions) that represent the models in your application code will also define these fields as required to ensure they always carry values at runtime. + +### Model attributes + +A field of a model can have one or more _attributes_ which modify the behaviour of the field. Field attributes are always prefixed with a single `@` (as opposed to block attributes which are prefixed with `@@`). You can find an overview of all available attributes [below](#attributes). + +## Models in Prisma Client + +### Queries (CRUD) + +Every model in the data model definition will result in a number of CRUD queries in the generated [Prisma Client API](): + +- `findMany` +- `findOne` +- `create` +- `update` +- `upsert` +- `delete` +- `updateMany` +- `deleteMany` + +The operations are accessible via a generated property on the Prisma Client instance. By default the name of the property is the lowercase form of the model name, e.g. `user` for a `User` model or `post` for a `Post` model. + +Here is an example illustrating the use of a `user` property from the Prisma Client API: + +```js +const newUser = await prisma.user.create({ + data: { + name: 'Alice', + }, +}) +const allUsers = await prisma.user.findMany() +``` + +### Type definitions + +Prisma Client not only provides a query API for models, it also generates type definitions that reflect your model structures. These are part of the generated [`@prisma/client`]() node module in a file called `index.d.ts`. + +When using TypeScript, these type definitions ensure that all your database queries are entirely type safe and validated at compile-time (even partial queries using [`select`]() or [`include`]()). When using plain JavaScript, the type definitions are still included in the generated `@prisma/client` node module, enabling features like [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense)/autocompletion in your editor. + +For example, the type definition for the `User` model from above would look as follows: + +```ts +export type User = { + id: number + email: string + name: string | null + role: string +} +``` + +Note that the relation fields `posts` and `profile` are not included in the type definion by default. However, if you need variations of the `User` type you can still define them using some of [Prisma Client's generated helper types]() (in this case, these helper types would be called `UserGetIncludePayload` and `UserGetSelectPayload`). + +### Requirements + +- Prisma currently requires every record of a model to be _uniquely_ identifiable. This means that you need to define _at least_ one `@unique`, `@@unique`, `@id` or `@@id` attribute per model. +- Prisma only supports models that are named according to this regular expression: + ``` + [A-Za-z_][A-Za-z0-9_]* + ``` + If your model name was generatd from introspection and doesn't adhere to this naming convention, you can use the `@@map` attribute to define a valid Prisma model name and map it to the non-allowed model name in your database. diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx new file mode 100644 index 0000000000..c867819d9c --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx @@ -0,0 +1,663 @@ +--- + title: "Relations" + metaTitle: "" + metaDescription: "" +--- + +## Overview + +This is an extension of the [Data model]() page which describes how to handle relations between Prisma models in the Prisma schema. + +Relations are represented via foreign keys in the underlying database. However, as opposed to how relations are modelled in SQL, **Prisma always requires explicit relation fields on _both_ sides of the relation to be set on your Prisma models**. This means that one of these relation fields represents the foreign key in the underlying database, the other relation field is a [virtual relation field](). + +## Example + +The examples on this page are based on the following schema file: + +```prima +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + +model User { + id Int @id @default(autoincrement()) + posts Post[] + profile Profile? +} + +model Profile { + id Int @id @default(autoincrement()) + user User +} + +model Post { + id Int @id @default(autoincrement()) + author User + categories Category[] +} + +model Category { + id Int @id @default(autoincrement()) + posts Post[] +} +``` + +> **Note**. This schema is the same as the [example data model](./data-modeling.md/#example) but has all [scalar fields](./data-modeling.md/#scalar-types) removed so you can focus on the relation fields. + +## Terminology + +### Cardinality + +There are three different [cardinalities]() of relations in Prisma: + +- One-to-one (also called 1-1-relation) +- One-to-many (also called 1-n-relation) +- Many-to-many (also called m-n-relation) + +In the example above, there are the following relations: + +- 1-1: `User` ↔ `Profile` +- 1-n: `User` ↔ `Post` +- m-n: `Post` ↔ `Category` + +### Relation fields + +Relation fields are fields on a Prisma [model]() that do _not_ have a [scalar type](). Instead, their type is another model. Consider these two models: + +```prisma +model User { + id Int @id @default(autoincrement()) + email String @unique + role Role @default(USER) + posts Post[] +} + +model Post { + id Int @id @default(autoincrement()) + title String + author User +} +``` + +These models have the following fields: + +| Model | Field | Type | Relation field | +| :----- | :------- | :------- | :-------------------- | +| `User` | `id` | `Int` | No | +| | `email` | `String` | No | +| | `role` | `Role` | No | +| | `posts` | `Post[]` | **Yes** (virtual) | +| `Post` | `id` | `Int` | No | +| | `title` | `String` | No | +| | `author` | `User` | **Yes** (foreign key) | + +Both `posts` and `author` are relation fields because their types are not scalar types but other models. + +Note that a relation field is always either backed by a foreign key in the underlying database or it is [virtual]() (which means that it's not "visible" in the schema of the underlying database). + +### Implicit vs explicit many-to-many relations + +Many-to-many relations can be either implicit or explicit in the Prisma schema. + +#### Explicit many-to-many relations + +Explicit many-to-many relations define an extra model which represents a _relation table_ (also sometimes called _JOIN_, _link_ or _pivot_ table) in the underlying database: + +```prisma +model Post { + id Int @id @default(autoincrement()) + categories Category[] +} + +model Category { + id Int @id @default(autoincrement()) + posts Post[] +} + +model CategoriesOnPosts { + post Post + category Category + + @@id([post, category]) +} +``` + +#### Implicit many-to-many relations + +Implicit many-to-many relations define relation fields as lists on both sides of the relation: + +```prisma +model Post { + id Int @id @default(autoincrement()) + categories Category[] +} + +model Category { + id Int @id @default(autoincrement()) + posts Post[] +} +``` + +Note that this m-n-relation is still manifested in a relation table in the underlying database. However, this relation table is managed by Prisma which makes the [Prisma Client API]() for many-to-many relations a bit simpler (since you e.g. have one fewer level of nesting inside of [nested writes]()). + +If you're not using Prisma Migrate but obtain your data model from [introspection](), you can still make use of implicit many-to-many relations by following Prisma's [conventions for relation tables](). + +### Relation tables + +A relation table (also sometimes called _JOIN_, _link_ or _pivot_ table) connects two or more other tables and therefore creates a _relation_ between them. Creating relation tables is a common data modeling practice in SQL to represent relationships between different entities. + +When using Prisma, you can create relation tables by defining [models]() similar to how you would model them as tables. The main difference is that the fields of the relation table are both relation fields that are backed by foreign keys (neither of them is virtual). + +Another use case for relation tables is to add "meta-information" to a relation. For example, _when_ the relation was created. + +Here is an example for a relation table called `CategoriesOnPosts`: + +```prisma +model Post { + id Int @id @default(autoincrement()) + categories Category[] +} + +model Category { + id Int @id @default(autoincrement()) + posts Post[] +} + +model CategoriesOnPosts { + post Post + category Category + createdAt DateTime @default(now()) + + @@id([post, category]) +} +``` + +In this example, the `createdAt` field stores additional information about the relation between `Post` and `Category` (i.e. it stores the point in time when "the post was added to the catgegory"). + +When you don't need to attach additional information to the relation, you can model m-n-relations as [implicit many-to-many relations](#implicit-many-to-many-relations). If you're not using Prisma Migrate but get your data model from introspection, you can s + +### Foreign key relation field + +Foreign key relation fields are relation fields that are backed by a foreign key in the underlying database. For + +### Virtual relation fields + +Virtual relation fields are relation fields in the Prisma schema that are not "manifested" in the database schema. + +There are two different kinds of virtual relation fields: + +- 1-1 and 1-n relations: One side of the relation represents a foreign key, the other side is a virtual relation field. +- m-n (implicit): Both relation fields are virtual since neither of them directly maps to a foreign key. + +Prisma always requires both sides of a relation to be present, this means that one virtual relation field always needs to be added per relation. When [formatting the Prisma schema](), the formatter automatically inserts any missing virtual relation fields for you to save some typing work. + +Virtual relation fields are also present in the generated [Prisma Client API]() which makes working with relations more convenient as you can traverse relationships in your code in both directions. + +## The @relation attribute + +The `@relation` attribute can only be applied to the [relation fields]() of a Prisma model, not to its [scalar fields](). In most cases the `@relation` attribute is optional, but it can be required, e.g. when: + +- you need to disambiguate a relation (that's e.g. the case when you have two relations between the same models) +- you need to determine on which side of the relation a foreign key should be used +- you need to control how the relation table is represented in the underlying database (e.g. use a specific name for a relation table) + +### Signature + +``` +@relation(_ name: String?, references: FieldReference[]?) +``` + +> **Note**: The leading underscore in the signature means that the argument name can be omitted. + +| Argument | Type | Required | Description | Example | +| :----------- | :----------------- | :------- | :---------------------------------------------------------------------------------------------------------------------- | :---------------------------------- | +| `name` | `String` | No | Defines the name of the relationship. In an m-n-relation, it also determines the name of the underlying relation table. | `"CategoryOnPost"`, `"MyRelation"` | +| `references` | `FieldReference[]` | No | A list of [fields]() | `["id"]`, `["firstName, lastName"]` | + +### Cases when the @relation attribute is required + +TBD + +## One-to-one relations + +One-to-one (1-1) relations refer to relations where at most one record can be connected on both sides of the relation. + +### Example + +In the example above, there's one 1-1-relation betwen `User` and `Profile`: + +```prisma +model User { + id Int @id @default(autoincrement()) + profile Profile? +} + +model Profile { + id Int @id @default(autoincrement()) + user User +} +``` + +This 1-1-relation expresses the following: + +- "a user can have zero or one profiles" (because the `profile` field is [optional]() on `User`) +- "a profile must always be connected to one user" + +In SQL, this is typically modeled as follows: + +```sql +CREATE TABLE "User" ( + id SERIAL PRIMARY KEY +); +CREATE TABLE "Profile" ( + id SERIAL PRIMARY KEY, + "user" integer NOT NULL UNIQUE, + FOREIGN KEY ("user") REFERENCES "User"(id) +); +``` + +Notice the `UNIQUE` constraint on the foreign key `user`. If this `UNIQUE` constrain was missing, the relation would be considered a 1-n relation. + +### Making both sides required in one-to-one relations + +When using Prisma, you can "augment" a 1-1-relation and make it required on _both_ sides: + +```prisma +model User { + id Int @id @default(autoincrement()) + name String + profile Profile +} + +model Profile { + id Int @id @default(autoincrement()) + bio String + user User +} +``` + +This 1-1-relation now expresses the following: + +- "a user must always have one profile" (because the `profile` field is [required]() on `User`) +- "a profile must always be connected to one user" + +Making the `profile` field on `User` required does not impact the schema in the underlying database since relational databases are not able to model such a constraint. This constraint is implemented and enforced by Prisma's [query engine](). + +It's important to note that in the case of required 1-1-relations, the only way to create a new record for either `User` or `Profile` is by using [nested writes](): + +```ts +const user = await prisma.user.create({ + data: { + name: "Alice" + create: { + profile: { + bio: "Hello World" + } + } + } +}) + +// or + +const user = await prisma.profile.create({ + data: { + bio: "I like turtles" + create: { + user: { + name: "Bob" + } + } + } +}) +``` + +If you're using [introspection](), you can make 1-1-relations required by manually adjusting your [Prisma schema]() and making both relation fields required, then you can [re-generate Prisma Client]() which will now make sure that the required 1-1-relation is enforced by the query engine. + +### Determining the side of the foreign key + +Consider again the above 1-1-relation between `User` and `Profile` where `profile` is optional on `User`: + +```prisma +model User { + id Int @id @default(autoincrement()) + profile Profile? +} + +model Profile { + id Int @id @default(autoincrement()) + user User +} +``` + +When using [Prisma Migrate](), this will create the foreign key on the `user` column of the `Profile` table in the underlying database. This is the only possible option because the `profile` relation field on `User` is actually [virtual](), so it can't be used as a foreign key. + +This is what the relation looks like in the database: + +![](https://imgur.com/N5wHT6D.png) + +If both of the relation fields in the relation would be either required or optional, Prisma Migrate assigns the foreign key to the table that comes first in the alphabet. + +**Both relation fields required** + +```prisma +model User { + id Int @id @default(autoincrement()) + profile Profile +} + +model Profile { + id Int @id @default(autoincrement()) + user User +} +``` + +**Both relation fields optional** + +```prisma +model User { + id Int @id @default(autoincrement()) + profile Profile? +} + +model Profile { + id Int @id @default(autoincrement()) + user User? +} +``` + +In both cases, the foreign key is being added to the `Profile` table because its name comes in the alphabet before `User`: + +![](https://imgur.com/N5wHT6D.png) + +However, in these cases you can still determine yourself on which side of the relation the foreign key should be stored by using the `@relation` attribute. To store the foreign key on `User` you need to add the `@relation` attribute to its relation field as follows: + +**Both relation fields required but using `@relation` to determine the foreign key** + +```prisma +model User { + id Int @id @default(autoincrement()) + profile Profile @relation(references: [id]) // references `id` of `Profile` +} + +model Profile { + id Int @id @default(autoincrement()) + user User +} +``` + +**Both relation fields optional but using `@relation` to determine the foreign key\*** + +```prisma +model User { + id Int @id @default(autoincrement()) + profile Profile? @relation(references: [id]) // references `id` of `Profile` +} + +model Profile { + id Int @id @default(autoincrement()) + user User? +} +``` + +In both cases, the foreign key is now defined on the `profile` column of the `User` table: + +![](https://imgur.com/NAd72ql.png) + +To summarize, these are the rules for determining which side of a 1-1-relation holds the foreign key: + +- If **one relation field is optional and the other one is required**, the required one holds the foreign key (as the other is [virtual]()). +- If **both relation fields are optional**, the one that comes first in the alphabet holds the foreign key. Note that this can be configured differently via the `@relation` attribute. +- If **both relation fields are required**, the one that comes first in the alphabet holds the foreign key. Note that this can be configured differently via the `@relation` attribute. + +Here's the summary in the form of a table assuming two generic models called `ModelA` and `ModelB`: + +| `ModelA`'s relation field | `ModelB`'s relation field | Foreign key on | `@relation` attribute | +| :------------------------ | :------------------------ | ------------------------------------------------------------ | ------------------------------------------------- | +| Required | Optional | `ModelA` (because the relation field on `ModelB` is virtual) | Can't be used to determine the foreign key | +| Optional | Required | `ModelB` (because the relation field on `ModelA` is virtual) | Can't be used to determine the foreign key | +| Optional | Optional | `ModelA` (because it's first in the alphabet) | Can be used to manually determine the foreign key | +| Required | Required | `ModelA` (because it's first in the alphabet) | Can be used to manually determine the foreign key | + +## One-to-many + +One-to-many (1-n) relations refer to relations where one record on one side of the relation can be connected to zero or more records on the other side. + +### One-to-one vs one-to-many relations + +In relational databases, the main difference between a 1-1 and a 1-n-relation is that in a 1-1-relation the foreign key must have a `UNIQUE` constraint defined on it. + +### Example + +In the example above, there's one 1-n-relation betwen `User` and `Post`: + +```prisma +model User { + id Int @id @default(autoincrement()) + posts Post[] +} + +model Post { + id Int @id @default(autoincrement()) + author User +} +``` + +Notice that the `posts` field on `User` is [virtual](), meaning that it's not manifested in the underlying database schema. + +This 1-n-relation expresses the following: + +- "a user can have zero or more posts" +- "a post must always have an author" + +In SQL, this is typically modeled as follows: + +```sql +CREATE TABLE "User" ( + id SERIAL PRIMARY KEY +); +CREATE TABLE "Post" ( + id SERIAL PRIMARY KEY, + author integer NOT NULL, + FOREIGN KEY (author) REFERENCES "User"(id) +); +``` + +Since there's no `UNIQUE` constraint on the `author` column (foreign key), you can create multiple `Post` records that point to the same `User` record therefore creating a one-to-many relationship between the two tables. + +### Required vs optional relation fields in one-to-many relations + +A 1-n-relation always has one [virtual]() relation field (which must be a [list]()) and a foreign key relation field. In the example above, `posts Post[]` on the `User` model is virtual, `author User` holds a foreign key. + +The relation fields in a relation can take the following forms: + +- the foreign key relation field can be either optional or required +- the virtual relation field must be a list and is always requireddat + +So, the following variant of the example above would be _allowed_: + +```prisma +model User { + id Int @id @default(autoincrement()) + posts Post[] +} + +model Post { + id Int @id @default(autoincrement()) + author User? // make `author` optional +} +``` + +But this one would be _not allowed_: + +```prisma +model User { + id Int @id @default(autoincrement()) + posts Post[]? // illegal +} + +model Post { + id Int @id @default(autoincrement()) + author User +} +``` + +## Many-to-many + +Many-to-many (m-n) relations refer to relations where zero or more records on one side of the relation can be connected to zero or more records on the other side. m-n-relations are typically modelled via [relation tables]() in a relational database. m-n-relations can be either [explicit]() or [implicit](). + +### Example + +In the example above, there's one _implicit_ m-n-relation betwen `Post` and `Category`: + +```prisma +model Post { + id Int @id @default(autoincrement()) + categories Category[] +} + +model Category { + id Int @id @default(autoincrement()) + posts Post[] +} +``` + +Notice that the `posts` field on `Category` and the `categories` field on `Post` both are [virtual](), meaning that they're not manifested in the underlying database schema. + +Insttead, the implicit many-to-many relation is maintained by Prisma with a [relation table]() that's not reflected in the Prisma schema. + +This m-n-relation expresses the following: + +- "a post can have zero or more categories" +- "a category can have zero or more posts" + +In SQL, this implicit m-n-relation maps to the following tables (following Prisma's [conventions for relation tables]()): + +```sql +CREATE TABLE "Category" ( + id SERIAL PRIMARY KEY +); +CREATE TABLE "Post" ( + id SERIAL PRIMARY KEY +); +-- Relation table + indexes ------------------------------------------------------- +CREATE TABLE "_CategoryToPost" ( + "A" integer NOT NULL REFERENCES "Category"(id), + "B" integer NOT NULL REFERENCES "Post"(id) +); +CREATE UNIQUE INDEX "_CategoryToPost_AB_unique" ON "_CategoryToPost"("A" int4_ops,"B" int4_ops); +CREATE INDEX "_CategoryToPost_B_index" ON "_CategoryToPost"("B" int4_ops); +``` + +![](https://imgur.com/DQClFIX.png) + +An _explicit_ variant of a similar m-n-relation would define an extra model to represent a relation table. In this case, you can also attach additional information to the relation (such as the point in time when it was created): + +```prisma +model Category { + id Int @default(autoincrement()) @id + categoryToPost CategoryToPost[] +} + +model Post { + id Int @default(autoincrement()) @id + categoryToPost CategoryToPost[] +} + +model CategoryToPost { + category Category + post Post + createdAt DateTime @default(now()) + + @@unique([category, post], name: "CategoryToPost_category_post_unique") +} +``` + +This would be represented as follows in SQL: + +```sql +CREATE TABLE "Category" ( + id SERIAL PRIMARY KEY +); +CREATE TABLE "Post" ( + id SERIAL PRIMARY KEY +); +-- Relation table + indexes ------------------------------------------------------- +CREATE TABLE "CategoryToPost" ( + "category" integer NOT NULL, + "post" integer NOT NULL, + "createdAt" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY ("category") REFERENCES "Category"(id), + FOREIGN KEY ("post") REFERENCES "Post"(id) +); +CREATE UNIQUE INDEX "CategoryToPost_category_post_unique" ON "CategoryToPost"("category" int4_ops,"post" int4_ops); +``` + +![](https://imgur.com/JQ22x60.png) + +### Conventions for relation tables in implicit m-n-relations + +If you're not using Prisma Migrate but obtain your data model from [introspection](), you can still make use of implicit many-to-many relations by following Prisma's conventions for relation tables. For the folowing example, assume you want to create a relation table to get an implicit many-to-many relation for two models called `Post` and `Category`. + +### Table name + +The name of the relation table consists of four parts: + +1. An underscore as a prefix: `_` +1. TBD + +Therefore, the relation name of the relation table is `_CategoryToPost`. + +This the a sample SQL statement that would create the three tables including indexes (in PostgreSQL dialect): + +```sql +CREATE TABLE "_CategoryToPost" ( + "A" integer NOT NULL REFERENCES "Category"(id) , + "B" integer NOT NULL REFERENCES "Post"(id) +); +CREATE INDEX "_CategoryToPost_B_index" ON "_CategoryToPost"("B" int4_ops); +CREATE TABLE "Category" ( + id integer DEFAULT nextval('"Category_id_seq"'::regclass) PRIMARY KEY +); +CREATE UNIQUE INDEX "Category_pkey" ON "Category"(id int4_ops); +CREATE TABLE "Post" ( + id integer DEFAULT nextval('"Post_id_seq"'::regclass) PRIMARY KEY +); +CREATE UNIQUE INDEX "Post_pkey" ON "Post"(id int4_ops); +``` + +#### Columns + +A relation table for an implicit-many-to-many relation must have exactly two columns: + +- A foreign key on `Category` that points to `Post` +- A foreign key on `Post` that points to `Category` + +You can name the columns whatever you like as long as you adhere to the [naming rules]() of Prisma fields. + +#### Unique index + +There further must be a unique index defined on both foreign key columns: + +```sql +CREATE UNIQUE INDEX "_CategoryToPost_AB_unique" ON "_CategoryToPost"("A" int4_ops,"B" int4_ops); +``` + + +## Self-relations + +A relation field can also reference its own model, in this case the relation is called a _self-relation_. Self-relations can be of any cardinality, 1-1, 1-n and m-n. + +### One-to-one self-relations + +A one-to-one self-relation looks as follows: + +### One-to-many self relations + +### Manyto-many self relations + +## Disambiguating relations From 32050e05582c923075b91ab8564bce42eea27878 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Fri, 20 Mar 2020 16:20:52 +0100 Subject: [PATCH 04/33] add more content --- .../01-tools-and-interfaces/02-prisma-client/index.mdx | 6 ++++++ .../01-tools-and-interfaces/03-prisma-migrate/index.mdx | 6 ++++++ .../{02-introspection.mdx => 04-introspection.mdx} | 1 - 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx rename content/03-reference/01-tools-and-interfaces/{02-introspection.mdx => 04-introspection.mdx} (76%) diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx new file mode 100644 index 0000000000..c25195ce2d --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx @@ -0,0 +1,6 @@ +--- + title: "Prisma Client" + metaTitle: "" + metaDescription: "" +--- + diff --git a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx new file mode 100644 index 0000000000..62f3e36f90 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx @@ -0,0 +1,6 @@ +--- + title: "Prisma Migrate" + metaTitle: "" + metaDescription: "" + experimental: true +--- \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-introspection.mdx b/content/03-reference/01-tools-and-interfaces/04-introspection.mdx similarity index 76% rename from content/03-reference/01-tools-and-interfaces/02-introspection.mdx rename to content/03-reference/01-tools-and-interfaces/04-introspection.mdx index 4afb3c4828..3357cbe124 100644 --- a/content/03-reference/01-tools-and-interfaces/02-introspection.mdx +++ b/content/03-reference/01-tools-and-interfaces/04-introspection.mdx @@ -2,5 +2,4 @@ title: "Introspection" metaTitle: "" metaDescription: "" - experimental: true --- \ No newline at end of file From 74ddf6b4b58c328543be5191e8313d7788c221de Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Fri, 20 Mar 2020 16:33:23 +0100 Subject: [PATCH 05/33] add prisma client content --- .../01-generating-prisma-client.mdx | 150 ++++ .../02-configuring-the-prisma-client-api.mdx | 239 ++++++ .../02-prisma-client/03-crud.mdx | 770 ++++++++++++++++++ .../02-prisma-client/04-relations.mdx | 7 + .../02-prisma-client/05-field-selection.mdx | 519 ++++++++++++ .../06-raw-database-access.mdx | 65 ++ .../07-connection-management.mdx | 71 ++ .../02-prisma-client/08-generated-types.mdx | 136 ++++ .../02-prisma-client/09-filtering.mdx | 7 + .../02-prisma-client/10-ordering.mdx | 7 + .../02-prisma-client/11-pagination.mdx | 7 + .../02-prisma-client/12-logging.mdx | 243 ++++++ .../02-prisma-client/13-debugging.mdx | 33 + .../02-prisma-client/14-error-formatting.mdx | 52 ++ .../02-prisma-client/15-transactions.mdx | 108 +++ .../02-prisma-client/16-deployment.mdx | 7 + .../02-prisma-client/17-query-engine.mdx | 80 ++ .../18-usage-with-module-bundlers.mdx | 18 + .../02-prisma-client/19-api.mdx | 9 + .../03-prisma-migrate/index.mdx | 3 +- .../04-introspection.mdx | 6 +- 21 files changed, 2535 insertions(+), 2 deletions(-) create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/03-crud.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relations.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/12-logging.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/13-debugging.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/16-deployment.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/18-usage-with-module-bundlers.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx new file mode 100644 index 0000000000..343bb28f9f --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx @@ -0,0 +1,150 @@ +--- +title: "Generating Prisma Client" +metaTitle: "" +metaDescription: "" +--- + +This page explains how to generate Prisma Client. Generating Prisma Client requires the Prisma CLI installed on your machine (learn more [here]()). + +Prisma Client is an auto-generated database client that's tailored to your database schema. By default, it lives inside your `node_modules` directory in `node_modules/@prisma/client`. This location can be adjusted if needed. + +Generating Prisma Client requires three steps: + +1. Add the following `generator` definition to your Prisma schema: + ```prisma + generator client { + provider = "prisma-client-js" + } + ``` +1. Install the `@prisma/client` npm module: + ``` + npm install @prisma/client + ``` +1. Generate Prisma Client with the following comand: + ``` + prisma generate + ``` + +**Important**: You need to re-execute the `prisma generate` command after every change that's made to your Prisma schema to update the generated Prisma Client code. + +Here is a graphical illustration of the typicaly workflow for the Prisma Client generation: + +![](https://imgur.com/fZ5rtVg.png) + +Note also that `prisma generate` is _automatically_ invoked when you're installing the `@prisma/client` npm module. So, when you're initially setting up Prisma Client, you can typically save the third step from the list above. + +Once generated, you can import and instantiate Prisma Client in your code as follows: + +```js +import { PrismaClient } from '@prisma/client' + +const prisma = new PrismaClient() +// use `prisma` in your application to read and write data in your DB +``` + +or + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() +// use `prisma` in your application to read and write data in your DB +``` + +## The `@prisma/client` npm module + +### How `@prisma/client` compares to "conventional" node modules + +The `@prisma/client` node module is different from "conventional" node modules. With conventional node modules, the entire package is downloaded into your `node_modules` directory and only gets updated when you re-install the package. + +As an example for such a module, consider the [`lodash`](https://lodash.com/) npm module. When you install it with `npm install lodash`, it gets downloaded and stored into `node_modules/lodash`. This `node_modules/lodash` directory doesn't change unless another `npm install` is invoked at some point (e.g. when an update of the package is available). + +The `@prisma/client` node module is different. It is a "facade package" (basically a stub) that doesn't contain any functional code, such as types or the Prisma Client runtime. + +While you do need to install it _once_ with `npm install @prisma/client`, it is likely that the code inside the `node_modules/@prisma/client` directory changes more often as you're evolving your application. This is because the directory contains code that is _generated_ based on your Prisma schema. When your Prisma schema changes (e.g. because you perform a [schema migration]()), you need to re-execute `prisma generate` which takes care of updating the code in `node_modules/@prisma/client` so that it reflects the schema changes. + +Because the `node_modules/@prisma/client` directory contains some code that is _specific_ to _your_ project, it is sometimes called a "smart node module". + +![](https://imgur.com/5HuBN2G.png) + +### Why is the "facade package" needed if Prisma Client is generated? + +The "facade package" is necessary to enable typical build and deployment workflows of Node.js applications. Here are a few examples for this: + +- This workflow allows teams to follow conventional practices for version control (because developers can clone repositories, run `npm install` and have the repo be ready without an extra step of running `prisma generate`). +- The facade package ensures that Prisma Client survives the [pruning](https://docs.npmjs.com/cli/prune.html) that's often employed by Node.js package managers. + +## Specifying the target location for Prisma Client + +The Prisma Client generator can be specified as follows in your schema file: + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Note that this is equivalent to specifying the default `output` path `./node_modules/@prisma/client`: + +```prisma +generator client { + provider = "prisma-client-js" + output = "./node_modules/@prisma/client" +} +``` + +After running `prisma generate` for either of these schema files, the Prisma Client package will be located in: + +``` +node_modules/@prisma/client +``` + +You can also specify a custom `output` path on the `generator` configuration, for example: + +```prisma +generator client { + provider = "prisma-client-js" + output = "./src/generated/client" +} +``` + +After running `prisma generate` for that schema file, the Prisma Client package will be located in: + +``` +./src/generated/client +``` + +## Why is Prisma Client generated into `node_modules/@prisma/client` by default? + +### Importing Prisma Client + +By generating Prisma Client into `node_modules/@prisma/client`, you can import it and instantiate it in your code as follows: + +```js +import { PrismaClient } from '@prisma/client' + +const prisma = new PrismaClient() + +// use `prisma` in your application to read and write data in your DB +``` + +or + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +// use `prisma` in your application to read and write data in your DB +``` + +### Keeping the query engine binary out of version control by default + +Prisma Client is based on a _query engine_ that's running as a sidecar process alongside your application. This query engine _binary_ is downloaded when `prisma generate` is invoked and stored in the `output` path. + +By generating Prisma Client into `node_modules`, the query engine is kept out of version control by default (since `node_modules` is typically ignored for version control). If it was not generated into `node_modules`, then you would need to explicitly ignore it, e.g. for Git you'd need to add the `output` path to your `.gitignore` file. + +## Generating Prisma Client in the `postinstall` hook of `@prisma/client` + +The `@prisma/client` package defines its own `postinstall` hook that's being executed whenever the package is being installed. This hook invokes the `prisma generate` command which in turn generates the Prisma Client code into the default location `node_modules/@prisma/client`. Notice that this requires the `prisma` CLI to be available, either as local dependency or as a global installation (it is recommended to always install the `prisma` package as a development dependency, using `npm install prisma --save-dev`, to avoid versioning conflicts though). + diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx new file mode 100644 index 0000000000..ccb7df6817 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx @@ -0,0 +1,239 @@ +--- +title: "Configuring the Prisma Client API" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +The Prisma Client API is generated based on the models in your [Prisma schema](). Models are _typically_ 1:1 mappings of your database tables. + +In some cases, especially when using [introspection](), it might be useful to _decouple_ the naming of database tables and columns from the names that are used in your Prisma Client API. This can be done via the `@map` and `@@map` attributes in your Prisma schema. + +## Example + +Assume you have a database schema looking similar to this: + +```sql +CREATE TABLE users ( + user_id SERIAL PRIMARY KEY NOT NULL, + name VARCHAR(256), + email VARCHAR(256) UNIQUE NOT NULL +); +CREATE TABLE posts ( + post_id SERIAL PRIMARY KEY NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + title VARCHAR(256) NOT NULL, + content TEXT, + author_id INTEGER REFERENCES users(user_id) +); +CREATE TABLE profiles ( + profile_id SERIAL PRIMARY KEY NOT NULL, + bio TEXT, + user_id INTEGER NOT NULL UNIQUE REFERENCES users(user_id) +); +CREATE TABLE categories ( + category_id SERIAL PRIMARY KEY NOT NULL, + name VARCHAR(256) +); +CREATE TABLE post_in_categories ( + post_id INTEGER NOT NULL REFERENCES posts(post_id), + category_id INTEGER NOT NULL REFERENCES categories(category_id) +); +CREATE UNIQUE INDEX post_id_category_id_unique ON post_in_categories(post_id int4_ops,category_id int4_ops); +``` + +When introspecting a database with that schema, you'll get a Prisma schema looking similar to this: + +```prisma +model categories { + category_id Int @default(autoincrement()) @id + name String? + post_in_categories post_in_categories[] +} + +model post_in_categories { + category_id categories + post_id posts + + @@unique([post_id, category_id], name: "post_id_category_id_unique") +} + +model posts { + content String? + created_at DateTime? + post_id Int @default(autoincrement()) @id + title String + author_id users? + post_in_categories post_in_categories[] +} + +model profiles { + bio String? + profile_id Int @default(autoincrement()) @id + user_id users +} + +model users { + email String @unique + name String? + user_id Int @default(autoincrement()) @id + posts posts[] + profiles profiles? +} +``` + +The are a few "issues" with this Prisma schema when the Prisma Client API is generated: + +**Adhering to Prisma's naming conventions** + +Prisma has a [naming convention]() of **camelCasing** and using the **singular form** for Prisma models. If these naming conventions are not met, the Prisma schema can become harder to interpret. Consider the following, generated model: + +```prisma +model users { + user_id Int @default(autoincrement()) @id + posts posts[] + profiles profiles? +} +``` + +Although `profiles` refers to a 1:1 relation, its type is currently called `profiles` in plural, suggesting that there might be many `profiles` in this relation. With Prisma conventions, the models and fields were _ideally_ named as follows: + +```prisma +model User { + user_id Int @default(autoincrement()) @id + posts Post[] + profile Profile? +} +``` + +**Naming of relation fields** + +Foreign keys are represented as _relation fields_ in the Prisma schema. Here's how all the relations from the SQL schema are represented: + +```prisma +model categories { + category_id Int @default(autoincrement()) @id + post_in_categories post_in_categories[] +} + +model post_in_categories { + category_id categories + post_id posts + + @@unique([post_id, category_id], name: "post_id_category_id_unique") +} + +model posts { + post_id Int @default(autoincrement()) @id + author_id users? + post_in_categories post_in_categories[] +} + +model profiles { + profile_id Int @default(autoincrement()) @id + user_id users +} + +model users { + user_id Int @default(autoincrement()) @id + posts posts[] + profiles profiles? +} +``` + +In the _database schema_, it makes sense to call the foreign key references after the referenced column, e.g. `post_id`, `user_id`. However, the mental model for relations in the Prisma schema is different. Here, the relation is referencing the _entire_ model, not only it's ID field. Therefore, the naming doesn't seem appropriate. + +The current naming of relation fields can also lead to confusion in the Prisma Client API, for example with [nested writes]() or the [fluent API](): + +```ts +// Nested writes +const profile = await prisma.profiles.create({ + data: { + bio: 'Hello World', + user_id: { + create: { + name: 'Alice', + email: 'alice@prisma.io' + } + } + } +}) + +// Fluent API +const userByProfile = await prisma.profiles.findOne({ + where: { id: 1 } +}).user_id() +``` + +In both cases, `user_id` is used to refer to an _entire_ "user object", not only to the `user_id` column. + +## Using `@map` and `@@map` to rename fields and models in the Prisma Client API + +You can "rename" fields and models that are used in the Prisma Client by mapping them to the "original" names in the database using the `@map` and `@@map` attributes. For the [example](#example) above, you could e.g. annotate your models as follows to prevent the mentioned issues. + +_After_ you introspected your database with `prisma introspect`, you can adjust the resulting Prisma schema as follows: + +```prisma +model Category { + category_id Int @default(autoincrement()) @id + post_in_categories post_in_categories[] + + @@map(name: "categories") +} + +model PostInCategories { + category Category @map(name: "category_id") + post Post @map(name: "post_id") + + @@unique([post, category], name: "post_id_category_id_unique") + @@map(name: "post_in_categories") +} + +model Post { + post_id Int @default(autoincrement()) @id + author User? @map(name: "author_id") + post_in_categories PostInCategories[] + + @@map(name: "posts") +} + +model Profile { + profile_id Int @default(autoincrement()) @id + user_id User @map(name: "user_id") + + @@map(name: "profiles") +} + +model User { + user_id Int @default(autoincrement()) @id + posts Post[] + profiles Profile? + + @@map(name: "users") +} +``` + +With these changes, you're now adhering to Prisma's naming conventions and the generated Prisma Client API feels more "natural": + +```ts +// Nested writess +const profile = await prisma.profile.create({ + data: { + bio: 'Hello World', + user: { + create: { + name: 'Alice', + email: 'alice@prisma.io' + } + } + } +}) + +// Fluent API +const userByProfile = await prisma.profile.findOne({ + where: { id: 1 } +}).user() +``` + +> **Warning**: `@map` and `@@map` attributes are removed when you run `prisma introspect` again. You might want to back up your Prisma schema with these attributes in order to not having to annotate everything from scratch again after a re-introspection. \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-crud.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-crud.mdx new file mode 100644 index 0000000000..ce9e6521c8 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-crud.mdx @@ -0,0 +1,770 @@ +--- +title: "CRUD" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +Prisma Client offers out-of-the-box support for several CRUD queries. CRUD stands for: + +- **C**reate +- **R**ead +- **U**pdate +- **D**elete + +The following CRUD queries are available in Prisma Client: + +- [`findOne`](#findOne) +- [`findMany`](#findMany) +- [`create`](#create) +- [`update`](#update) +- [`updateMany`](#updateMany) +- [`upsert`](#upsert) +- [`delete`](#delete) +- [`deleteMany`](#deleteMany) +- [`count`](#count) + +This page contains a detailled description for each query. Unless otherwise noted, the examples on this page are based on the following Prisma schema: + +```prisma +model User { + id Int @id @default(autoincrement()) + name String? + email String @unique + profileViews Int @default(0) + role Role @default(USER) + coinflips Boolean[] + posts Post[] +} + +model Post { + id Int @id @default(autoincrement()) + title String + published Boolean @default(true) + author User +} + +enum Role { + USER + ADMIN +} +``` + +CRUD queries are exposed by the _model properties_ on your `PrismaClient` instance. Taking the `User` and `Post` models from above as examples, you'd invoke the CRUD queries via the `prisma.user` and `prisma.post` model properties, e.g.: + +```ts +await prisma.user.create({ data: { name: 'Alice' } }) +// or +await prisma.post.findMany() +``` + +## findOne + +The `findOne` query lets you retrieve a single database record of a model based on an _ID_ or _unique_ attribute. You can use the `select` and `include` arguments to determine which fields should be included on the returned model object. + +### Options + +#### Type + +`findOne` takes as input an object of the following type: + +```ts +export type FindOneUserArgs = { + where: UserWhereUniqueInput + select?: UserSelect | null + include?: UserInclude | null +} +``` + +These are further relevant generated types: + +```ts +export type UserWhereUniqueInput = { + id?: number | null + email?: string | null +} +``` + +
Expand for a multi-field ID/unique example + +In case your model has a multi-field ID or unique attribute such as the following: + +```prisma +model User { + firstName String + lastName String + + @@id([firstName, lastName]) +} +``` + +The `UserWhereUniqueInput` input looks slightly different: + +```ts +export type UserWhereUniqueInput = { + firstName_lastName?: FirstNameLastNameCompoundUniqueInput | null +} + +export type FirstNameLastNameCompoundUniqueInput = { + firstName: string + lastName: string +} +``` + +
+ +#### Reference + +| Name | Type | Required | Description | +| --------- | ---------------------- | -------- | -------------------------------------------------------------------------------- | +| `where` | `UserWhereUniqueInput` | **Yes** | Wraps all _unique_ fields of a model so that individual records can be selected. | +| `select` | `UserSelect` | No | Specifies which fields to include on the returned model object. | +| `include` | `UserInclude` | No | Specifies which relations should be eagerly loaded on the returned model object. | + +### Return type + +`findOne` returns a plain old JavaScript object or `null`. + +The type of the object that's returned by a `findOne` API call depends on whether you use the `select` and `include` options. + +If you use neither of these options, the return type will correspond to the TypeScript type that's generated for the model. For the `User` model from above, this type looks as follows: + +```ts +export type User = { + id: number + name: string | null + email: string + role: Role + coinflips: boolean[] + profileViews: number +} +``` + +### Examples + +#### Single-field ID or unique attribute + +**Retrieve the `User` record with an `id` of `42`**: + +```ts +const result = await prisma.user.findOne({ + where: { + id: 42, + }, +}) +``` + +**Retrieve the `User` record with an `email` of `alice@prisma.io`**: + +```ts +const result = await prisma.user.findOne({ + where: { + email: 'alice@prisma.io', + }, +}) +``` + +#### Multi-field ID or unique attribute + +Assume your model has a multi-field ID or unique attribute, e.g.: + +```prisma +model User { + firstName String + lastName String + + @@id([firstName, lastName]) +} +``` + +**Retrieve the `User` record with `firstName` of `Alice` and `lastName` of `Smith`**: + +```ts +const result = await prisma.user.findOne({ + where: { + firstName_lastName: { + firstName: 'Alice', + lastName: 'Smith', + }, + }, +}) +``` + +## findMany + +The `findMany` query retrieves a list of records. The list can be altered using [pagination](), [filtering]() and [ordering]() arguments. You can use the `select` and `include` arguments to determine which fields should be included on each model object in the returned list. + +### Options + +#### Type + +`findMany` takes as input an object of the following type: + +```ts +export type FindManyUserArgs = { + select?: UserSelect | null + include?: UserInclude | null + where?: UserWhereInput | null + orderBy?: UserOrderByInput | null + skip?: number | null + after?: UserWhereUniqueInput | null + before?: UserWhereUniqueInput | null + first?: number | null + last?: number | null +} +``` + +These are further relevant generated types: + +```ts +export type UserWhereInput = { + id?: number | IntFilter | null + name?: string | NullableStringFilter | null + email?: string | StringFilter | null + role?: Role | RoleFilter | null + profileViews?: number | IntFilter | null + posts?: PostFilter | null + AND?: Enumerable | null + OR?: Enumerable | null + NOT?: Enumerable | null +} + +export type PostFilter = { + every?: PostWhereInput | null + some?: PostWhereInput | null + none?: PostWhereInput | null +} + +export type UserWhereUniqueInput = { + id?: number | null + email?: string | null +} + +export type UserOrderByInput = { + id?: OrderByArg | null + name?: OrderByArg | null + email?: OrderByArg | null + role?: OrderByArg | null + profileViews?: OrderByArg | null +} + +export declare const OrderByArg: { + asc: 'asc' + desc: 'desc' +} +``` + +#### Reference + +| Name | Type | Required | Description | +| --------- | ---------------------- | -------- | ----------------------------------------------------------------------------------------------------------- | +| `where` | `UserWhereInput` | No | Wraps _all_ fields of a model so that the list can be filtered by any model property. | +| `orderBy` | `UserOrderByInput` | No | Lets you order the returned list by any model property. | +| `skip` | `string` | No | Specifies how many of the returned objects in the list should be skipped. | +| `after` | `UserWhereUniqueInput` | No | Specifies the starting object for the list (the value typically specifies an `id` or another unique value). | +| `before` | `UserWhereUniqueInput` | No | Specifies the last object for the list (the value typically specifies an `id` or another unique value). | +| `first` | `number` | No | Specifies how many elements should be returned in the list (as seen from the _beginning_ of the list). | +| `last` | `number` | No | Specifies how many elements should be returned in the list (as seen from the _end_ of the list). | +| `select` | `UserSelect` | No | Specifies which fields to include on the returned model object. | +| `include` | `UserInclude` | No | Specifies which relations should be eagerly loaded on the returned model object. | + +### Return type + +`findMany` returns an array of plain old JavaScript objects. + +The type of the objects in the array that's returned by a `findMany` API call depend on whether you use the `select` and `include` options. + +If you use neither of these options, the return type will correspond to the TypeScript type that's generated for the model. For the `User` model from above, this type looks as follows: + +```ts +export type User = { + id: number + name: string | null + email: string + role: Role + coinflips: boolean[] + profileViews: number +} +``` + +### Examples + +**Retrieve all `User` records where the `name` is `Alice`**: + +```ts +const user = await prisma.user.findMany({ + where: { name: 'Alice' }, +}) +``` + +## create + +The `create` query creates a new database record. You can use the `select` and `include` arguments to determine which fields should be included on the returned model object. + +### Options + +#### Type + +`create` takes as input an object of the following type: + +```ts +export type UserCreateArgs = { + select?: UserSelect | null + include?: UserInclude | null + data: UserCreateInput +} +``` + +These are further relevant generated types: + +```ts +export type UserCreateInput = { + name?: string | null + email: string + role?: Role | null + profileViews: number + coinflips?: UserCreatecoinflipsInput | null + posts?: PostCreateManyWithoutAuthorInput | null +} + +export type UserCreatecoinflipsInput = { + set?: Enumerable | null +} + +export type PostCreateManyWithoutAuthorInput = { + create?: Enumerable | null + connect?: Enumerable | null +} + +export type PostCreateWithoutAuthorInput = { + title: string + published?: boolean | null +} + +export type PostWhereUniqueInput = { + id?: number | null +} +``` + +#### Reference + +| Name | Type | Required | Description | +| --------- | ----------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `data` | `UserCreateInput` | **Yes** | Wraps all the fields of the model so that they can be provided when creating new records. It also includes relation fields which lets you perform (transactional) nested inserts. Fields that are marked as optional or have default values in the datamodel are optional. | +| `select` | `UserSelect` | No | Specifies which fields to include on the returned model object. | +| `include` | `UserInclude` | No | Specifies which relations should be eagerly loaded on the returned model object | + +### Return type + +`create` returns a plain old JavaScript object. + +The type of the object that's returned by a `create` API call depends on whether you use the `select` and `include` options. + +If you use neither of these options, the return type will correspond to the TypeScript type that's generated for the model. For the `User` model from above, this type looks as follows: + +```ts +export type User = { + id: number + name: string | null + email: string + role: Role + coinflips: boolean[] + profileViews: number +} +``` + +### Examples + +**Create a new record with the only required field `email`**: + +```ts +const user = await prisma.user.create({ + data: { email: 'alice@prisma.io' }, +}) +``` + +## update + +The `update` query updates an existing database record. You can use the `select` and `include` arguments to determine which fields should be included on the returned model object. + +### Options + +#### Type + +`update` takes as input an object of the following type: + +```ts +export type UserUpdateArgs = { + select?: UserSelect | null + include?: UserInclude | null + data: UserUpdateInput + where: UserWhereUniqueInput +} +``` + +These are further relevant generated types: + +```ts +export type UserWhereUniqueInput = { + id?: number | null + email?: string | null +} + +export type UserUpdateInput = { + id?: number | null + name?: string | null + email?: string | null + role?: Role | null + profileViews?: number | null + coinflips?: UserUpdatecoinflipsInput | null + posts?: PostUpdateManyWithoutAuthorInput | null +} + +export type UserUpdatecoinflipsInput = { + set?: Enumerable | null +} + +export type PostUpdateManyWithoutAuthorInput = { + create?: Enumerable | null + connect?: Enumerable | null + set?: Enumerable | null + disconnect?: Enumerable | null + delete?: Enumerable | null + update?: Enumerable | null + updateMany?: Enumerable | null + deleteMany?: Enumerable | null + upsert?: Enumerable | null +} +``` + +#### Reference + +| Name | Type | Required | Description | +| --------- | ---------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `data` | `UserUpdateInput` | **Yes** | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional. | +| `where` | `UserWhereUniqueInput` | **Yes** | Wraps all _unique_ fields of a model so that individual records can be selected. | +| `select` | `UserSelect` | No | Specifies which fields to include on the returned model object. | +| `include` | `UserInclude` | No | Specifies which relations should be eagerly loaded on the returned model object. | + +### Return type + +`update` returns a plain old JavaScript object or `null`. + +The type of the object that's returned by a `update` API call depends on whether you use the `select` and `include` options. + +If you use neither of these options, the return type will correspond to the TypeScript type that's generated for the model. For the `User` model from above, this type looks as follows: + +```ts +export type User = { + id: number + name: string | null + email: string + role: Role + coinflips: boolean[] + profileViews: number +} +``` + +### Examples + +**Update the `email` of the `User` record with `id` of `1` to `alice@prisma.io`**: + +```ts +const user = await prisma.user.update({ + where: { id: 1 }, + data: { email: 'alice@prisma.io' }, +}) +``` + +## upsert + +The `upsert` query updates an existing or creates a new database record. You can use the `select` and `include` arguments to determine which fields should be included on the returned model object. + +### Options + +#### Type + +`upsert` takes as input an object of the following type: + +```ts +export type UserUpsertArgs = { + select?: UserSelect | null + include?: UserInclude | null + where: UserWhereUniqueInput + create: UserCreateInput + update: UserUpdateInput +} +``` + +Refer to [`findOne`](#findOne), [`create`](#create) and [`update`](#update) to see what the generated types `UserWhereUniqueInput`, `UserCreateInput` and `UserUpdateInput` types look like. + +#### Reference + +| Name | Type | Required | Description | +| --------- | ---------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `create` | `UserCreateInput` | **Yes** | Wraps all the fields of the model so that they can be provided when creating new records. It also includes relation fields which lets you perform (transactional) nested inserts. Fields that are marked as optional or have default values in the datamodel are optional. | +| `update` | `UserUpdateInput` | **Yes** | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional. | +| `where` | `UserWhereUniqueInput` | **Yes** | Wraps all _unique_ fields of a model so that individual records can be selected. | +| `select` | `UserSelect` | No | Specifies which fields to include on the returned model object. | +| `include` | `UserInclude` | No | Specifies which relations should be eagerly loaded on the returned model object. | + +### Return type + +`upsert` returns a plain old JavaScript object. + +The type of the object that's returned by a `upsert` API call depends on whether you use the `select` and `include` options. + +If you use neither of these options, the return type will correspond to the TypeScript type that's generated for the model. For the `User` model from above, this type looks as follows: + +```ts +export type User = { + id: number + name: string | null + email: string + role: Role + coinflips: boolean[] + profileViews: number +} +``` + +### Examples + +**Update (if exists) or create a new `User` record with an `email` of `alice@prisma.io`**: + +```ts +const user = await prisma.user.upsert({ + where: { id: 1 }, + update: { email: 'alice@prisma.io' }, + create: { email: 'alice@prisma.io' }, +}) +``` + +## delete + +The `delete` query deletes an existing database record. Even though the record is being deleted, `delete` still returns the model object that was deleted. You can use the `select` and `include` arguments to determine which fields should be included on the returned model object. + +### Options + +#### Type + +`delete` takes as input an object of the following type: + +```ts +export type FindOneUserArgs = { + where: UserWhereUniqueInput + select?: UserSelect | null + include?: UserInclude | null +} +``` + +These are further relevant generated types: + +```ts +export type UserWhereUniqueInput = { + id?: number | null + email?: string | null +} +``` + +
Expand for a multi-field ID/unique example + +In case your model has a multi-field ID or unique attribute such as the following: + +```prisma +model User { + firstName String + lastName String + + @@id([firstName, lastName]) +} +``` + +The `UserWhereUniqueInput` input looks slightly different: + +```ts +export type UserWhereUniqueInput = { + firstName_lastName?: FirstNameLastNameCompoundUniqueInput | null +} + +export type FirstNameLastNameCompoundUniqueInput = { + firstName: string + lastName: string +} +``` + +
+ +#### Reference + +| Name | Type | Required | Description | +| --------- | ---------------------- | -------- | -------------------------------------------------------------------------------- | +| `where` | `UserWhereUniqueInput` | **Yes** | Wraps all _unique_ fields of a model so that individual records can be selected. | +| `select` | `UserSelect` | No | Specifies which fields to include on the returned model object. | +| `include` | `UserInclude` | No | Specifies which relations should be eagerly loaded on the returned model object. | + +### Return type + +`findOne` returns a plain old JavaScript object. + +The type of the object that's returned by a `findOne` API call depends on whether you use the `select` and `include` options. + +If you use neither of these options, the return type will correspond to the TypeScript type that's generated for the model. For the `User` model from above, this type looks as follows: + +```ts +export type User = { + id: number + name: string | null + email: string + role: Role + coinflips: boolean[] + profileViews: number +} +``` + +### Examples + +**Delete the `User` record with an `id` of `1`**: + +```ts +const user = await prisma.user.delete({ + where: { id: 1 }, +}) +``` + +## updateMany + +The `updateMany` query updates a batch of existing database records in bulk and returns the number of deleted records. + +### Options + +#### Type + +`updateMany` takes as input an object of the following type: + +```ts +export type UserUpdateManyArgs = { + data: UserUpdateManyMutationInput + where?: UserWhereInput | null +} +``` + +These are further relevant generated types: + +```ts +export type UserUpdateManyMutationInput = { + id?: number | null + name?: string | null + email?: string | null + role?: Role | null + profileViews?: number | null + coinflips?: UserUpdatecoinflipsInput | null +} + +export type UserUpdatecoinflipsInput = { + set?: Enumerable | null +} + +export type UserWhereInput = { + id?: number | IntFilter | null + name?: string | NullableStringFilter | null + email?: string | StringFilter | null + role?: Role | RoleFilter | null + profileViews?: number | IntFilter | null + posts?: PostFilter | null + AND?: Enumerable | null + OR?: Enumerable | null + NOT?: Enumerable | null +} +``` + +#### Reference + +| Name | Type | Required | Description | +| ------- | ----------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `data` | `UserUpdateManyMutationInput` | **Yes** | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional on `data`. | +| `where` | `UserWhereInput` | No | Wraps _all_ fields of a model so that the list can be filtered by any model property. If not provide, all models are being updated. | + +### Return type + +`updateMany` returns an object of type `BatchPayload` wihch is defined as follows: + +```ts +export type BatchPayload = { + count: number +} +``` + +The value of `count` is an integer and represents the number of records that have been updated by the method. + +### Examples + +**Update all `User` records where the `name` is `Alice` to `ALICE`**: + +```ts +const updatedUserCount = await prisma.user.updateMany({ + where: { name: 'Alice' }, + data: { name: 'ALICE' }, +}) +``` + +## deleteMany + +The `deleteMany` query deletes a batch of existing database records in bulk and returns the number of deleted records. + +### Options + +#### Type + +`deleteMany` takes as input an object of the following type: + +```ts +export type UserWhereInput = { + id?: number | IntFilter | null + name?: string | NullableStringFilter | null + email?: string | StringFilter | null + role?: Role | RoleFilter | null + profileViews?: number | IntFilter | null + posts?: PostFilter | null + AND?: Enumerable | null + OR?: Enumerable | null + NOT?: Enumerable | null +} +``` + +#### Reference + +| Name | Type | Required | Description | +| ------- | ---------------- | -------- | ------------------------------------------------------------------------------------- | +| `where` | `UserWhereInput` | No | Wraps _all_ fields of a model so that the list can be filtered by any model property. | + +### Return type + +`deleteMany` returns an object of type `BatchPayload` wihch is defined as follows: + +```ts +export type BatchPayload = { + count: number +} +``` + +The value of `count` is an integer and represents the number of records that have been deleted by the method. + +### Examples + +**Delete all `User` records where the `name` is `Alice`**: + +```ts +const deletedUserCount = await prisma.user.deleteMany({ + where: { name: 'Alice' }, +}) +``` + +### `count` + +To return the number of elements in a list, you can the `count()` method on any model property on your `PrismaClient` instance, for example: + +```ts +const userCount = await prisma.user.count() +// userCount = 42 +``` \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relations.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relations.mdx new file mode 100644 index 0000000000..5717a0335a --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relations.mdx @@ -0,0 +1,7 @@ +--- +title: "Relations" +metaTitle: "" +metaDescription: "" +--- + +Coming soon 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx new file mode 100644 index 0000000000..339acdd12c --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx @@ -0,0 +1,519 @@ +--- +title: "Field selection" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This section explains how to predict and control which fields of a model are returned in a Prisma Client API call by using the [`select`](#select) and [`include`](#include) options. + +Unless otherwise noted, the examples on this page are based on the following Prisma schema: + +```prisma +model User { + id Int @id @default(autoincrement()) + name String? + email String @unique + profileViews Int @default(0) + role Role @default(USER) + coinflips Boolean[] + posts Post[] +} + +model Post { + id Int @id @default(autoincrement()) + title String + published Boolean @default(true) + author User +} + +enum Role { + USER + ADMIN +} +``` + +## Selection sets + +To understand which fields are being returned by a certain API call, you need to be aware of its **selection set**. + +The selection set defines the **set of fields on a model instance that is returned in a Prisma Client API call**. + +Consider the following example `findOne` invocation: + +```ts +const result = await prisma.user.findOne({ + where: { id: 1 }, +}) +``` + +The `result` of this API call is a plain old JavaScript object that might look similar to this: + +```js +{ + id: 1, + name: "Alice", + email: "alice@prisma.io", + profileViews: 0, + role: "ADMIN", + coinflips: [true, false], +} +``` + +All the fields that are contained in this object are scalar fields, enums or arrays of scalar fields. + +## The default selection set + +If the selection set is not manipulated (via `select` or `include`), a Prisma Client API call returns the **default selection set** for a model. It includes all [_scalar_](./data-modeling.md#scalar-types) fields (including [enums](./data-modeling.md#enums) and arrays/scalar lists) fields of the model. + +Considering the sample datamodel from above: + +- The default selection set for the `User` model includes `id`, `name`, `email`, `profileViews`, `role` and `coinflips`. It does **not** include `posts` because that's a _relation_ and not a scalar field. +- The default selection set for the `Post` model includes `id`, `title` and `published`. It does **not** include `author` because that's a _relation_ and not a scalar field. + +## Manipulating the selection set + +There are two ways how the _default selection set_ can be manipulated to specify which fields should be returned by a Prisma Client API call: + +- **Select exclusively** (via `select`): When using `select`, the selection set only contains the fields that are explicitly provided as arguments to `select`. +- **Include additionally** (via `include`): When using `include`, the default selection set gets extended with additional fields that are provided as arguments to `include`. + +Note that you can nest `select` and `include` statements but they can't be provided right next to ech other. For example, the following combination is allowed: + +```ts +const result = await prisma.user.findMany({ + select: { + id: true, + name: true, + posts: { + include: { + author: true, + }, + }, + }, +}) +``` + +And the following one is not allowed because `select` and `include` appear on the same level of nesting right next to each other: + +```ts +const result = await prisma.user.findMany({ + select: { + id: true, + name: true, + }, + include: { + posts: true, + }, +}) +``` + +This case would be caught with the following exceptions: + +``` +Invalid `prisma.user.findMany()` invocation: + +{ + select: { + ~~~~~~ + id: true, + name: true + }, + include: { + ~~~~~~~ + posts: true + } +} + + +Please either use `include` or `select`, but not both at the same time. +``` + +Both, `select` and `include` are available as options on the following methods: + +- [`findOne`](#findOne) +- [`findMany`](#findMany) +- [`create`](#create) +- [`update`](#update) +- [`upsert`](#upsert) +- [`delete`](#delete) + +## `select` + +When providing the `select` option to a Prisma Client API call, only those fields are included on the returned model object that are explicitly specified. The `select` option is an object that contains _all_ fields of a model with a boolean value indicating whether this field should be included in the response. + +### Type + +The type of the `select` option is custom for each model. For example, for the `User` and `Post` models from above the types look as follows: + +```ts +export type UserSelect = { + id?: boolean + name?: boolean + email?: boolean + role?: boolean + coinflips?: boolean + profileViews?: boolean + posts?: boolean | FindManyPostArgs +} + +export type PostSelect = { + id?: boolean + title?: boolean + published?: boolean + author?: boolean | UserArgs +} +``` + +The types also contain relation fields which can be even further controlled with specific arguments: + +```ts +export type UserArgs = { + select?: UserSelect | null + include?: UserInclude | null +} + +export type FindManyPostArgs = { + select?: PostSelect | null + include?: PostInclude | null + where?: PostWhereInput | null + orderBy?: PostOrderByInput | null + skip?: number | null + after?: PostWhereUniqueInput | null + before?: PostWhereUniqueInput | null + first?: number | null + last?: number | null +} +``` + +You can read more about the additional types on `FindManyPostArgs` [here](). + +### Examples + +In this example, we're using `select` to exclusively select the `name` field of the returned `User` object: + +```ts +const result = await prisma.user.findOne({ + where: { id: 1 }, + select: { + name: true, + profileViews: true, + }, +}) +``` + +The `result` object now looks as follows: + +```js +{ + name: "Alice", + profileViews: 0 +} +``` + +You can do the same on any other query listed above, e.g. on `findMany`: + +```ts +const result = await prisma.user.findMany({ + select: { + email: true, + role: true, + }, +}) +``` + +Since `findMany` returns an array of objects, `result` would now look as follows: + +```js +;[ + { + email: 'alice@prisma.io', + role: 'ADMIN', + }, + { + email: 'bob@prisma.io', + role: 'USER', + }, +] +``` + +Here's how you can include additional fields of a relation: + +```ts +const result = await prisma.user.findMany({ + select: { + id: true, + name: true, + posts: { + select: { + id: true, + title: true, + }, + }, + }, +}) +``` + +In this case, the result might look as follow: + +```ts +;[ + { + id: 1, + name: 'Alice', + posts: [ + { id: 1, title: 'Hello World' }, + { id: 2, title: 'Bye bye' }, + ], + }, + { + id: 2, + name: 'Bob', + posts: [], + }, +] +``` + +You can also nest the `include` option inside of the `select` option: + +```ts +const result = await prisma.user.findMany({ + select: { + id: true, + name: true, + posts: { + include: { + author: true, + }, + }, + }, +}) +``` + +This would result in the following structure for the `result` object: + +```js +[ + { + id: 1, + name: 'Alice', + posts: [ + { + id: 1, + title: 'Hello World', + published: true, + author: { + id: 1, + name: 'Alice', + email: 'alice@prisma.io', + role: 'ADMIN', + coinflips: [true, false], + profileViews: 0, + }, + }, + { + id: 2, + title: 'Bye bye', + published: false, + author: { + id: 1, + name: 'Alice', + email: 'alice@prisma.io', + role: 'USER', + coinflips: [], + profileViews: 0, + }, + }, + ], + }, +] +``` + +Note that the `author` contains all fields of the `User` model's default selection set (scalars, arrays/scalar lists, enums). + +## `include` + +Sometimes you want to directly include a relation when retrieving data from a database (this is sometimes called "eager loading"). To include the relations of a model in an API call, you can use the `include` options. + +### Type + +The type of the `include` option is custom for each model. For example, for the `User` and `Post` models from above the types look as follows: + +```ts +export type UserInclude = { + posts?: boolean | FindManyPostArgs +} + +export type PostInclude = { + author?: boolean | UserArgs +} +``` + +The types contain only relation fields which can be even further controlled with specific arguments: + +```ts +export type UserArgs = { + select?: UserSelect | null + include?: UserInclude | null +} + +export type FindManyPostArgs = { + select?: PostSelect | null + include?: PostInclude | null + where?: PostWhereInput | null + orderBy?: PostOrderByInput | null + skip?: number | null + after?: PostWhereUniqueInput | null + before?: PostWhereUniqueInput | null + first?: number | null + last?: number | null +} +``` + +You can read more about the additional types on `FindManyPostArgs` [here](). + +### Examples + +```ts +const result = await prisma.user.findOne({ + where: { id: 1 }, + include: { posts: true }, +}) +``` + +The `result` object in this case contains the [default selection set]() of the `User` model _plus_ its `posts` relation: + +```js +{ + id: 1, + name: "Alice", + email: "alice@prisma.io", + role: "ADMIM", + coinflips: [true], + profileViews: 0, + posts: [ + { + id: 1, + title: "Hello World", + published: true + }, + { + id: 2, + title: "Bye bye", + published: false + } + ] +} +``` + +You can also nest `include` and `select` statements: + +```ts +const result = await prisma.user.findOne({ + where: { id: 1 }, + include: { + posts: { + select: { + published: true, + title: true + } + } + } +}) +``` + +This would lead to the following structure of the `result` object: + +```js +{ + id: 1, + name: "Alice", + email: "alice@prisma.io", + role: "USER", + coinflips: [true], + profileViews: 0, + posts: [ + { + published: true, + title: "Hello World" + }, + { + published: false, + title: "Bye bye" + } + ] +} +``` + + +The nesting and combinations can be arbitrarily deep: + +```ts +const result = await prisma.user.findOne({ + where: { id: 1 }, + include: { + posts: { + select: { + published: true, + title: true, + author: { + select: { + id: true, + posts: { + select: { + title: true + } + } + } + } + } + } + } +}) +``` + +In this case, the `result` object would look as follows: + +```js +{ + id: 1, + name: "Alice", + email: "alice@prisma.io", + role: "USER", + coinflips: [true], + profileViews: 0, + posts: [ + { + published: true, + title: "Hello World", + author: { + id: 1, + posts: [ + { + title: "Hello World" + }, + { + title: "Bye bye" + } + ] + } + }, + { + published: false, + title: "Bye bye", + author: { + id: 1, + posts: [ + { + title: "Hello World" + }, + { + title: "Bye bye" + } + ] + } + } + ] +} +``` \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx new file mode 100644 index 0000000000..28ed1f570b --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx @@ -0,0 +1,65 @@ +--- +title: "Raw database access" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +You can send raw SQL queries to your database using the `raw` function that's exposed by your `PrismaClient` instance. It returns the query results as plain old JavaScript objects: + +```ts +const result = await prisma.raw('SELECT * FROM User;') +``` + +`result` is an array where each object corresponds to a retrieved database record: + +```js +[ + { "id":1, "email":"sarah@prisma.io", "name":"Sarah" }, + { "id":2, "email":"alice@prisma.io", "name":"Alice" } +] +``` + +## Tagged templates + +The `raw` method is implemented as a [tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates). Therefore, you can also call `raw` as follows: + +```ts +const result = await prisma.raw`SELECT * FROM User;` +``` + +## Setting variables + +To include variables in your SQL query, you can use JavaScript string interpolation with [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals): + +```ts +const userId = 42 +const result = await prisma.raw`SELECT * FROM User WHERE id = ${userId};` +``` + +## Typing `raw` results + +The `raw` function has the following function signature: + +```ts +raw(query: string | TemplateStringsArray): Promise; +``` + +The return type of `raw` is a `Promise` for the [generic](https://www.typescriptlang.org/docs/handbook/generics.html) type parameter `T`. This means you can type the result manually by providing `T` when you invoke `raw`. If you don't provide any type, the return type of `raw` defaults to `any`. + +```ts +// import the generated `User` type from the `@prisma/client` module +import { User } from '@prisma/client' + +const result = await prisma.raw('SELECT * FROM User;') +// result is of type: `User[]` +``` + +Now, `result` is statically typed to the generated `User` type (or rather an array thereof) from Prisma Client. + +![](https://imgur.com/H2TCRc5.png) + +If you're selecting only specific fields of the model or want to include relations, read the documentation about [leveraging Prisma Client's generated types](./generated-types.md) if you want to ensure that the query results are properly typed. + +Note that calls to `SELECT` always return arrays of type `T`, but other SQL operations (like `INSERT` or `UPDATE`) might return single objects. \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx new file mode 100644 index 0000000000..29ffaa85dc --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx @@ -0,0 +1,71 @@ +--- +title: "Connection management" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +Prisma Client connects and disconnects from your data sources using the following two methods: + +- `connect(): Promise` +- `disconnect(): Promise` + +Unless you want to employ a specific optimization, calling `prisma.connect()` is not necessary thanks to the _lazy connect_ behavior: The `PrismaClient` instance connects lazily when the first request is made to the API (`connect()` is called for you under the hood). + +If you need the first request to respond instantly and can't wait for the lazy connection to be established, you can explicitly call `prisma.connect()` to establish a connection to the Prisma data source: + +```ts +const prisma = new PrismaClient() + +// run inside `async` function +await prisma.connect() +``` + +**IMPORTANT**: It is recommended to always explicitly call `prisma.disconnect()` in your code. Also, be sure to disconnect even when an exception is thrown: + +```ts +main() + .catch(e => { + throw e + }) + .finally(async () => { + await prisma.disconnect() + }) +``` + +## `connect` + +The `connect` method establishes a physical connection to the database via Prisma's [query engine](). + +Note that `connect` returns a `Promise`, so you shsould call it inside an `async` function with the `await` keyword. + +## `disconnect` + +The `disconnect` method closes the database connections that were established when `connect` was called and stops the process that was running Prisma's query engine. + +Note that `connect` returns a `Promise`, so you should call it inside an `async` function with the `await` keyword. + +## Connection pool + +Once `connect` was called, the query engine immediately creates a connection pool with the amount of connections that were specified as the `connection_limit` parameter on your database connection URL. + +For example, with the following `datasource` configuration in your [Prisma schema]() the connection pool will have exactly five connections: + +```prisma +datasource postgresql { + provider = "postgresql" + url = "postgresql://johndoe:mypassword@localhost:5432/mydb?connection_limit=5" +} +``` + +If the `connection_limit` argument is omitted, the default number of connecctions is calculated according to this formula: `num_physical_cpus * 2 + 1` where `num_physical_cpus` represents the number of physical CPUs on your machine. + +```prisma +datasource postgresql { + provider = "postgresql" + url = "postgresql://johndoe:mypassword@localhost:5432/mydb" +} +``` + +If your machine four physical CPUs, your connection pool will contain nine connections (`4 * 2 + 1 = 9`). diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx new file mode 100644 index 0000000000..89ab96e202 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx @@ -0,0 +1,136 @@ +--- +title: "Advanced usage of generated types" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +The generated code for Prisma Client contains a number of helpful types that you can use to make your application more type-safe. This page describes patterns for leveraging some of the generated types. + +Note that you can find all type definitions inside the `index.d.ts` file inside the [generated `@prisma/client` node module](). + +## Operating against partial structures of your model types + +When using Prisma Client, every model from your [Prisma schema]() is translated into a dedicated TypeScript type. For example, assume you have the following `User` and `Post` models: + +```prisma +model User { + id Int @id + email String @unique + name String? + posts Post[] +} + +model Post { + id Int @id + author User + title String + published Boolean @default(false) +} +``` + +The Prisma Client code that's generated from this schema contains this representation of the `User` type: + +```ts +export declare type User = { + id: string; + email: string; + name: string | null; +}; +``` + +### Problem: Using variations of the generated model type + +#### Description + +In some scenarios, you may need a _variation_ of the generated `User` type. For example, when you have a function that expects an instance of the `User` model that carries the `posts` relation. Or when you need a type to pass only the `User` model's `email` and `name` fields around in your application code. + +#### Solution + +As a solution, you can customize the generated model type using Prisma Client's helper types. + +The `User` type only contains the model's [scalar]() fields, but doesn't account for any relations. That's because [relations are not included by default]() in Prisma Client' API calls. + +However, sometimes it's useful to have a type available that **includes a relation** (i.e. a type that you'd get from an API call that uses [`include`]()). Similarly, another useful scenario could be to have a type available that **includes only a subset of the model's scalar fields** (i.e. a type that you'd get from an API call that uses [`select`](). + +One way of achieving this would be to define these types manually in your application code: + +```ts +// Define a type that includes the relation to `Post` +type UserWithPosts = { + id: string; + email: string; + name: string | null; + posts: Post[] +} + +// Define a type that only contains a subset of the scalar fields +type UserPersonalData = { + email: string; + name: string | null; +} +``` + +While this is certainly feasible, this approach increases the maintenance burden upon changes to the Prisma schema as you need to manually maintain the types. A cleaner solution to this is to use the `UserGetIncludePayload` and `UserGetSelectPayload` types that are generated and exposed by Prisma Client: + +```ts +import { UserGetIncludePayload, UserGetSelectPayload } from '@prisma/client' + +// Define a type that includes the relation to `Post` +type UserWithPosts = UserGetIncludePayload<{ + posts: true +}> + +// Define a type that only contains a subset of the scalar fields +type UserPersonalData = UserGetSelectPayload<{ + email: true; + name: true; +}> +``` + +The main benefits of the latter approach are: + +- Cleaner approach as it leverages Prisma Client's generated types +- Reduced maintenance burden and improved type safety when the schema changes + +### Problem: Getting access to the return type of a function + +#### Description + +When doing [`select`]() or [`include`]() operations on your models and returning these variants from a function, it can be difficult to gain access to the return type, e.g: + +```ts +// Function definition that returns a partial structure +async function getUsersWithPosts() { + const users = await prisma.user.findMany({ include: { posts: true } }) + return users +} +``` + +Extracting the type that represents "users with posts" from the above code snippet requires some advanced TypeScript usage: + +```ts +// Function definition that returns a partial structure +async function getUsersWithPosts() { + const users = await prisma.user.findMany({ include: { posts: true } }) + return users +} + +// Extract `UsersWithPosts` type with +type ThenArg = T extends PromiseLike ? U : T; +type UsersWithPosts = ThenArg>; + +// run inside `async` function +const usersWithPosts: UsersWithPosts = await getUsersWithPosts() +``` + +#### Solution + +With the `PromiseReturnType` that is exposed by Prisma Client, you can solve this more elegantly: + +```ts +import { PromiseReturnType } from '@prisma/client' + +type UsersWithPosts = PromiseReturnType; +``` \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx new file mode 100644 index 0000000000..7e87d21456 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx @@ -0,0 +1,7 @@ +--- +title: "Filtering" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx new file mode 100644 index 0000000000..ae8a5cac23 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx @@ -0,0 +1,7 @@ +--- +title: "Ordering" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx new file mode 100644 index 0000000000..8e42391ca2 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx @@ -0,0 +1,7 @@ +--- +title: "Pagination" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/12-logging.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/12-logging.mdx new file mode 100644 index 0000000000..2a9b125f63 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/12-logging.mdx @@ -0,0 +1,243 @@ +--- +title: "Logging" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +You can view the generated database queries that Prisma Client JS sends to your database as well as warnings and other information by configuring different _log levels_ in the `PrismaClient` constructor. You can do this via the `log` option: + +```ts +const prisma = new PrismaClient({ + log: ['query', 'info', 'warn'], +}) +``` + +This logs all log levels: + +- `query`: Logs the SQL queries that are generated by a Prisma Client API call +- `info`: Logs general information +- `warn`: Logs warnings + +## The `log` option + +### Type + +The `log` options is optional and has the following type: + +```ts +log?: Array +``` + +If the `log` option is not provided, nothing will be logged. + +Here's the type definitions for `LogLevel` and `LogDefinition`: + +```ts +type LogLevel = 'info' | 'query' | 'warn' +type LogDefinition = { + level: LogLevel + emit: 'stdout' | 'event' +} +``` + +By default, logs are printed to [stdout](https://en.wikipedia.org/wiki/Standard_streams) so you can directly observe them. Alternatively, you can also configure event-based logging and observe the logs by providing a callback to the `on()` function. + +### Logging to stdout + +If you want to print your logs to stdout, you can provide the `LogLevel` values directly to the `log` option: + +```ts +const prisma = new PrismaClient({ + log: ['query', 'info', 'warn'], +}) +``` + +Since stdout is the default, the above code snippet is equivalent to the following one where you're explicitly passing `stdout` to the `emit` option: + +```ts +const prisma = new PrismaClient({ + log: [ + { + emit: 'stdout', + level: 'query', + }, + { + emit: 'stdout', + level: 'info', + }, + { + emit: 'stdout', + level: 'warn', + }, + ], +}) +``` + +### Event-based logging + +If you want to apply some custom logic to your logs, you can also set `emit` to `event`: + +```ts +const prisma = new PrismaClient({ + log: [ + { + emit: 'event', + level: 'query', + }, + { + emit: 'event', + level: 'info', + }, + { + emit: 'event', + level: 'warn', + }, + ], +}) + +// ... must now call prisma.on(...) in order to handle the logging events +``` + +If you do this, you need to call the `.on` function on your `PrismaClient` instance and provide a callback function which then receives the logging event. Depending on the selected log level, the input event will carry different arguments. + +#### Logging `query` events + +Here is a sample snippet that shows how to log an incoming event `e` (for the log level `query`): + +```ts +const prisma = new PrismaClient({ + log: [ + { + emit: 'event', + level: 'query', + }, + ], +}) + +prisma.on('query', e => { + e.timestamp + e.query + e.params + e.duration + e.target + console.log(e) +}) +``` + +The incoming event `e` is of type `QueryEvent` which is defined as follows: + +```ts +export type QueryEvent = { + timestamp: Date + query: string + params: string + duration: number + target: string +} +``` + +Note that `query` contains the SQL query and `params` contains any query parameters for the SQL query. + +
Expand to see a logging example + +With the above configuration, assume you're sending the following query with Prisma Client: + +```ts +const allPosts = await prisma.post.findMany({ + where: { published: true }, + include: { + author: true, + }, +}) +``` + +This API call generates two SQL queries that are being sent as events to the callback configured via `on()`. Here's a sample for what these events might look like: + +```js +{ + timestamp: 2020-03-10T08:36:57.430Z, + query: 'SELECT `dev`.`Post`.`id`, `dev`.`Post`.`title`, ' + + '`dev`.`Post`.`content`, `dev`.`Post`.`published`, ' + + '`dev`.`Post`.`author` FROM `dev`.`Post` WHERE ' + + '`dev`.`Post`.`published` = ? LIMIT ? OFFSET ?', + params: '[true,-1,0]', + duration: 0, + target: 'quaint::connector::metrics' +} +{ + timestamp: 2020-03-10T08:36:57.430Z, + query: 'SELECT `dev`.`User`.`id`, `dev`.`User`.`email`, `dev`.`User`.`name` ' + + 'FROM `dev`.`User` WHERE `dev`.`User`.`id` IN (?,?) LIMIT ? OFFSET ?', + params: '[3,2,-1,0]', + duration: 0, + target: 'quaint::connector::metrics' +} +``` + +
+ +#### Logging `info` events + +Here is a sample snippet that shows how to log an incoming event `e` (for the log level `info`): + +```ts +const prisma = new PrismaClient({ + log: [ + { + emit: 'event', + level: 'info', + }, + ], +}) + +prisma.on('info', e => { + e.timestamp + e.duration + e.target + console.log(e) +}) +``` + +The incoming event `e` is of type `LogEvent` which is defined as follows: + +```ts +export type LogEvent = { + timestamp: Date + message: string + target: string +} +``` + +#### Logging `warn` events + +Here is a sample snippet that shows how to log an incoming event `e` (for the log level `warn`): + +```ts +const prisma = new PrismaClient({ + log: [ + { + emit: 'event', + level: 'warn', + }, + ], +}) + +prisma.on('warn', e => { + e.timestamp + e.duration + e.target + console.log(e) +}) +``` + +The incoming event `e` is of type `LogEvent` which is defined as follows: + +```ts +export type LogEvent = { + timestamp: Date + message: string + target: string +} +``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/13-debugging.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/13-debugging.mdx new file mode 100644 index 0000000000..e321d65a44 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/13-debugging.mdx @@ -0,0 +1,33 @@ +--- +title: "Debugging" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +You can enable debugging output in Prisma Client via the `DEBUG` environment variable. It accepts two namespaces to print debugging output: + +- `engine`: Prints relevant debug messages happening in a Prisma [engine](https://github.com/prisma/prisma-engines/) +- `prisma-client`: Prints relevant debug messages happening in the Prisma Client runtime + +## Setting the `DEBUG` environment variable + +Here are examples for setting these debugging options in bash: + +```bash +# enable only `engine`-level debugging output +export DEBUG="engine" + +# enable only `prisma-client`-level debugging output +export DEBUG="prisma-client" + +# enable both `prisma-client`- and `engine`-level debugging output +export DEBUG="prisma-client,engine" +``` + +If you want to enable all debugging options, you can also set `DEBUG` to `*`: + +```bash +export DEBUG="*" +``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx new file mode 100644 index 0000000000..6b18e36988 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx @@ -0,0 +1,52 @@ +--- +title: "Error formatting" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +By default, Prisma Client uses [ANSI escape characters](https://en.wikipedia.org/wiki/ANSI_escape_code) to pretty print the error stack and give recommendations on how to fix a problem. While this is very useful when using Prisma Client from the terminal, in contexts like a GraphQL API, you only want the minimal error without any additional formatting. + +This page explains how error formatting can be configured with Prisma Client. + +## Formatting levels + +There are 3 error formatting levels: + +1. **Pretty Error** (default): Includes a full stack trace with colors, syntax highlighting of the code and extended error message with a possible solution for the problem. +2. **Colorless Error**: Same as pretty errors, just without colors. +3. **Minimal Error**: The raw error message. + +In order to configure these different error formatting levels, there are two options: + +- Setting the config options via environment variables +- Providing the config options to the `PrismaClient` constructor + +## Formatting via environment variables + +- `NO_COLOR`: If this env var is provided, colors are stripped from the error message. Therefore you end up with a **colorless error**. The `NO_COLOR` environment variable is a standard described [here](https://no-color.org/). +- `NODE_ENV=production`: If the env var `NODE_ENV` is set to `production`, only the **minimal error** will be printed. This allows for easier digestion of logs in production environments. + +### Formatting via the `PrismaClient` constructor + +The constructor argument to control the error formatting is called `errorFormat`. It can have the following values: + +- `undefined`: If it's not defined, the default is `pretty`. +- `pretty`: Enables pretty error formatting. +- `colorless`: Enables colorless error formatting. +- `minimal`: Enables minimal error formatting. + +It can be used like so: + +```ts +const prisma = new PrismaClient({ + errorFormat: 'minimal', +}) +``` + +As the `errorFormat` property is optional, you still can just instantiate Prisma Client like this: + +```ts +const prisma = new PrismaClient() +``` \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx new file mode 100644 index 0000000000..d3a64e8f0a --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx @@ -0,0 +1,108 @@ +--- +title: "Transactions" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +A _database transaction_ refers to a sequence of read/write operations that are _guaranteed_ to either succeed or fail as a whole. + +Transactions are a great tool since they allow developers to disregard a number of potential concurrency problems that can occur when a database processes multiple operations in a short amount of time. Developers take advantage of the _safety guarantees_ provided by the database by wrapping the operations in a transaction. + +These guarantees are often summarized using the ACID acronym: + +- **Atomic**: Ensures that either _all_ or _none_ operations of the transactions succeed. The transaction is either _committed_ successfully or _aborted_ and _rolled back_. +- **Consistent**: Ensures that the states of the database before and after the transaction are _valid_ (i.e. any existing invariants about the data are maintained). +- **Isolated**: Ensures that concurrently running transactions have the same effect as if they were running in serial. +- **Durability**: Ensures that after the transaction succeeded, any writes are being stored persistently. + +While there's a lot of of ambiguity and nuance to each of these properties (e.g. consistency could actually be considered an _application-level responsibility_ rather than a database property or isolation is typically guaranteed in terms of stronger and weaker _isolation levels_), overall they serve as a good high-level guideline for expectations developers have when thinking about database transactions. + +> "Transactions are an abstraction layer that allows an application to pretend that certain concurrency problems and certain kinds of hardware and software faults don’t exist. A large class of errors is reduced down to a simple transaction abort, and the application just needs to try again." **[Designing Data-Intensive Applications](https://dataintensive.net/), [Martin Kleppmann](https://twitter.com/martinkl)** + +## How Prisma Client supports transactions today + +Prisma Client provides a data access API to read and write data from a database. For relational databases, Prisma Client's API abstracts over SQL where transactions are a common feature. + +While Prisma Client doesn't allow for the same flexibility a SQL-level transaction provides, it covers the vast majority of use cases developers have for transactions with [**nested writes**](). + +A nested write lets you perform a single Prisma Client API call with multiple _operations_ that touch multiple [_related_](./relations.md#nested-writes) records, for example creating a _user_ together with a _post_ or updating an _order_ together with an _invoice_. When a nested write is performed, Prisma Client ensures that it will either succeed or fail as a whole. + +Here are examples for nested writes in the Prisma Client API: + +```ts +// Create a new user with two posts in a +// single transaction +const newUser: User = await prisma.user.create({ + data: { + email: 'alice@prisma.io', + posts: { + create: [ + { title: 'Join the Prisma Slack on https://slack.prisma.io' }, + { title: 'Follow @prisma on Twitter' }, + ], + }, + }, +}) +``` + +```ts +// Change the author of a post in a single transaction +const updatedPost: Post = await prisma.post.update({ + where: { id: 42 }, + data: { + author: { + connect: { email: 'alice@prisma.io' }, + }, + }, +}) +``` + +## Future transaction support in Prisma Client + +Transactions are a commonly used feature in relational as well as non-relational databases and Prisma Client might support more transaction mechanisms in the future. Specifically, the following two use cases might be supported: + +- Sending multiple operations in bulk +- Enabling longer-running transactions where operations can depend on each other + + +### Bulk operations + +The first use case of sending multiple operations in bulk could be implemented with an API similar to this: + +```ts +const write1 = prisma.user.create() +const write2 = prisma.orders.create() +const write3 = prisma.invoices.create() + +await prisma.transaction([write1, write2, write3]) +``` + +Instead of immediately awaiting the result of each operation when it's performed, the operation itself is stored in a variable first which later is submitted to the database via a method called `transaction`. Prisma Client will ensure that either all three `create`-operations or none of them succeed. + +### Long-running transactions + +The second use case of longer-running transactions where operations can depend on each other is a bit more involved. Prisma Client would need to expose a _transaction API_ which enables developers to initiate and commit a transaction themselves while Prisma Client takes care of ensuring the safety guarantees associated with transactions. It could look similar to this: + +```ts +prisma.transaction(async tx => { + const user = await tx.users.create({ + data: { email: "alice@prisma.io" } + }) + const order = await tx.orders.create({ + data: { + customer: { + connect: { id: user.id } + } + } + }) + await tx.commit() +}) +``` + +In this case, the API provides a way to wrap a sequence of operations in a callback which gets executed as a transaction, therefore is guaranteed to either succeed or fail as a whole. + +### Join the conversation on GitHub + +If you'd like to see transactions supported in the future, [please join the discussion on GitHub](https://github.com/prisma/prisma-client-js/issues/349). \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-deployment.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-deployment.mdx new file mode 100644 index 0000000000..d213e5cbeb --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-deployment.mdx @@ -0,0 +1,7 @@ +--- +title: "Deployment" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx new file mode 100644 index 0000000000..7d18c524ba --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx @@ -0,0 +1,80 @@ +--- +title: "Query engine" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +From a technical perspective, Prisma Client consists of three major components: + +- JavaScript client library +- TypeScript type definitions +- A query engine (in the form of binary file) + +All of these components are located in the [generated `@prisma/client` node module]() after you ran `prisma generate`. + +This page covers relevant technical details about the query engine. + +### The query engine binary file + +The **query engine binary file** is called `query-engine-PLATFORM` where `PLATFORM` corresponds to the name of a compile target. For example, if the query engine must run on a [Darwin](https://en.wikipedia.org/wiki/Darwin_(operating_system)) operating system (e.g. Mac OS), it's called `query-engine-darwin`. You can find an overview of all supported platforms [here](). + +The query engine binary file is downloaded into the `runtime` directory of `node_modules/@prisma/client` when `prisma generate` is called. + +Note that the query engine is implemented in Rust. The source code is located in the [`prisma-engines`](https://github.com/prisma/prisma-engines/) repository. + + +## The query engine at runtime + +The query engine is running as a separate process on the same machine where the Node.js/TypeScript application is running. + +![](https://imgur.com/XI3uXXA.png) + +The query engine process is started when the [`connect()`]() method is called on your `PrismaClient` instance. Once the process is started, the query engine creates a [connnection pool]() and manages the physical connections to the database. From that point onwards, Prisma Client is ready to send [queries]() to the database (e.g. `findOne`, `findMany`, `create`, ...). + +The query engine process is stopped and the database connections are closed when [`disconnect()`]() is invoked. + +The following diagram depicts a "typical flow": + +1. `connect()` is invoked on Prisma Client +1. The query engine process is started +1. The query engine establishes connections to the database and creates connection pool +1. Prisma Client is now ready to send queries to the database +1. Prisma Client sends a `findMany()` query to the query engine +1. The query engine translates the query into SQL and sends it to the database +1. The query engine receives the SQL response from the database +1. The query engine returns the result as plain old JavaScipt objects to Prisma Client +1. `disconnect()` is invoked on Prisma Client +1. The query engine closes the database connections +1. The query engine process is stopped + +![](https://imgur.com/Z9L3Cez.png) + +## Responsibilities of the query engine + +The query engine has the following responsibilities in an application that uses Prisma Client: + +- manage physical database connections in connection pool +- receive incoming queries from the Prisma Client Node.js process +- generate SQL queries +- send SQL queries to the database +- process responses from the database and send them back to Prisma Client + +## Debugging the query engine + +You can access the logs of the query engine by setting the [`DEBUG`]() environment variable to `engine`: + +```bash +export DEBUG="engine" +``` + +You can also get more visibility into the SQL queries that are generated by the query engine by setting the `query` log level in Prisma Client: + +```ts +const prisma = new PrismaClient({ + log: ['query'] +}) +``` + +Learn more in the [debugging]() and [logging]() sections of the docs. \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-usage-with-module-bundlers.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-usage-with-module-bundlers.mdx new file mode 100644 index 0000000000..de7282c61d --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-usage-with-module-bundlers.mdx @@ -0,0 +1,18 @@ +--- +title: "Usage with module bundlers" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +_Module bundlers_ bundle JavaScript modules into a single JavaScript file. Most bundlers work by copying over the JavaScript code from a variety of source files into the target file. + +Since Prisma Client is not only based on JavaScript code, but also relies on the [**query engine binary file**]() to be available, you need to make sure that your bundled code has access to the binary file. + +To do so, you can use plugins that let you copy over static assets: + +| Bundler | Plugin | +| :------ | :-------------------------------------------------------------------------------------------------- | +| Webpack | [`copy-webpack-plugin`](https://github.com/webpack-contrib/copy-webpack-plugin#copy-webpack-plugin) | +| Parcel | [`parcel-plugin-static-fil | diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx new file mode 100644 index 0000000000..a89bc818fe --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx @@ -0,0 +1,9 @@ +--- + title: "Prisma Client API" + metaTitle: "" + metaDescription: "" +--- + +## Overview + +Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx index 62f3e36f90..3f7aa439eb 100644 --- a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx @@ -3,4 +3,5 @@ metaTitle: "" metaDescription: "" experimental: true ---- \ No newline at end of file +--- + diff --git a/content/03-reference/01-tools-and-interfaces/04-introspection.mdx b/content/03-reference/01-tools-and-interfaces/04-introspection.mdx index 3357cbe124..632f57374c 100644 --- a/content/03-reference/01-tools-and-interfaces/04-introspection.mdx +++ b/content/03-reference/01-tools-and-interfaces/04-introspection.mdx @@ -2,4 +2,8 @@ title: "Introspection" metaTitle: "" metaDescription: "" ---- \ No newline at end of file +--- + +## Overview + +Coming 🔜 \ No newline at end of file From 5addae1fe3ea1dc3410e021c432949ee12119ee9 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Fri, 20 Mar 2020 16:48:05 +0100 Subject: [PATCH 06/33] add remaining content for reference --- .../04-introspection.mdx | 2 - .../05-prisma-cli/01-installation.mdx | 100 ++++ .../05-prisma-cli/02-command-reference.mdx | 543 ++++++++++++++++++ .../05-prisma-cli/index.mdx} | 2 +- .../02-database-connectors/01-postgresql.mdx | 7 + .../02-database-connectors/02-mysql.mdx | 7 + .../02-database-connectors/03-sqlite.mdx | 7 + .../index.mdx | 0 .../03-reference/03-more/01-editor-setup.mdx | 7 + content/03-reference/03-more/02-telemetry.mdx | 71 +++ content/03-reference/03-more/index.mdx | 6 + content/04-guides/index.mdx | 5 + 12 files changed, 754 insertions(+), 3 deletions(-) create mode 100644 content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx rename content/03-reference/{02-more/01-roadmap.mdx => 01-tools-and-interfaces/05-prisma-cli/index.mdx} (67%) create mode 100644 content/03-reference/02-database-connectors/01-postgresql.mdx create mode 100644 content/03-reference/02-database-connectors/02-mysql.mdx create mode 100644 content/03-reference/02-database-connectors/03-sqlite.mdx rename content/03-reference/{02-more => 02-database-connectors}/index.mdx (100%) create mode 100644 content/03-reference/03-more/01-editor-setup.mdx create mode 100644 content/03-reference/03-more/02-telemetry.mdx create mode 100644 content/03-reference/03-more/index.mdx create mode 100644 content/04-guides/index.mdx diff --git a/content/03-reference/01-tools-and-interfaces/04-introspection.mdx b/content/03-reference/01-tools-and-interfaces/04-introspection.mdx index 632f57374c..ef4759859a 100644 --- a/content/03-reference/01-tools-and-interfaces/04-introspection.mdx +++ b/content/03-reference/01-tools-and-interfaces/04-introspection.mdx @@ -4,6 +4,4 @@ metaDescription: "" --- -## Overview - Coming 🔜 \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx new file mode 100644 index 0000000000..6d180408c0 --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx @@ -0,0 +1,100 @@ +--- +title: "Installation" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +The Prisma 2 CLI is available as an [npm package](). It is **recommended to install the Prisma 2 CLI locally** in your project's `package.json` to avoid version conflicts. + +## Local installation (recommended) + +The Prisma 2 CLI is typically installed as a **development dependency**, that's why the `--save-dev` (npm) and `--dev` (Yarn) options are used in the commands below. + +#### npm + +Install with npm: + +``` +npm install prisma2 --save-dev +``` + +This should add `prisma2` to the `devDependencies` in your `package.json`. You can then invoke the locally installed `prisma2` CLI by prefixing it with [`npx`](https://github.com/npm/npx#readme): + +``` +npx prisma2 +``` + +Here's an example for invoking the `generate` command: + +``` +npx prisma2 generate +``` + +#### Yarn + +Install with Yarn: + +``` +yarn add prisma2 dev +``` + +This should add `prisma2` to the `devDependencies` in your `package.json`. You can then invoke the locally installed `prisma2` CLI by prefixing it with `yarn`: + +``` +yarn prisma2 +``` + +Here's an example for invoking the `generate` command: + +``` +yarn prisma2 generate +``` + +## Global installation + +While it is recommended to [locally install](#local-installation-recommended) the `prisma2` CLI, you can also install it globally on your machine. + +> **Warning**: If you have several Prisma projects on your machine, a global installation can lead to version conflicts between these projects. + +#### npm + +Install with npm: + +``` +npm install -g prisma2 +``` + +You can then invoke the globally installed `prisma2` CLI like so: + +``` +prisma2 +``` + +Here's an example for invoking the `generate` command: + +``` +prisma2 generate +``` + + +#### Yarn + +Install with Yarn: + +``` +yarn global add prisma2 +``` + +You can then invoke the globally installed `prisma2` CLI like so: + +``` +prisma2 +``` + +Here's an example for invoking the `generate` command: + +``` +prisma2 generate +``` \ No newline at end of file diff --git a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx new file mode 100644 index 0000000000..0a8130fa9c --- /dev/null +++ b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx @@ -0,0 +1,543 @@ +--- +title: "CLI command reference" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +The Prisma command line interface (CLI) is the primary way to interact with your Prisma project from the command line. It can initialize new project assets, generate Prisma Client, and analyze existing database structures through introspection to automatically create your application models. + +Along with these features, there are also a few experimental commands that you you can access if you'd like to use in-progress functionality (e.g. Prisma Migrate or Prisma Studio). + +This document will explain the Prisma CLI's commands, arguments, and options. + +## Synopsis + +The `prisma2` command can be called from command line once installed. When called without arguments, it will display its command usage and help document: + +```shell +prisma2 +``` +``` +◭ Prisma is a modern DB toolkit to query, migrate and model your database (https://prisma.io) + +Usage + + $ prisma2 [command] + +Commands + + init Setup Prisma for your app + introspect Get the datamodel of your database + generate Generate artifacts (e.g. Prisma Client) + +Flags + + --experimental Show and run experimental Prisma commands + +Examples + + Setup a new Prisma project + $ prisma2 init + + Introspect an existing database + $ prisma2 introspect + + Generate artifacts (e.g. Prisma Client) + $ prisma2 generate +``` + +You can get additional help on any of the `prisma2` commands by adding the `--help` flag after the command. + +## Commands + +### init + +Bootstraps a fresh Prisma project within the current directory. + +The `init` command does not interpret any existing files. Instead, it creates a `prisma` directory containing a bare-bones `schema.prisma` file within your current directory. + +#### Examples + +**Run `prisma2 init`** + +```shell +prisma2 init +``` +``` +✔ Your Prisma schema was created at prisma/schema.prisma. + You can now open it in your favorite editor. + +Next steps: +1. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql or sqlite. +2. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started. +3. Run prisma2 introspect to turn your database schema into a Prisma data model. +4. Run prisma2 generate to install Prisma Client. You can then start querying your database. + +More information in our documentation: +https://pris.ly/d/getting-started +``` + +The command output contains helpful information on how to use the generated files and begin using Prisma with your project. + +#### Generated Assets + +**`prisma/schema.prisma`** + +A minimal `schema.prisma` file to define your schema in: + +```prisma +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} +``` + +**`prisma/.env`** + +A file to define environment variables for your project: + +``` +# Environment variables declared in this file are automatically made available to Prisma. +# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables + +# Prisma supports the native connection string format for PostgreSQL, MySQL and SQLite. +# See the documentation for all the connection string options: https://pris.ly/d/connection-strings + +DATABASE_URL="postgresql://johndoe:johndoe@localhost:5432/mydb?schema=public" +``` + +### generate + +The `generate` command generates assets like Prisma Client based on the [`generator`](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md#generators-optional) and [`model`](https://github.com/prisma/prisma2/blob/master/docs/data-modeling.md) blocks defined in your `prisma/schema.prisma` file. + +The `generate` command is most often used to generate Prisma Client with the `prisma-client-js` generator. This does three things: + +1. Searches the current directory and parent directories to find the applicable `npm` project. It will create a `package.json` file in the current directory if it cannot find one. +2. Installs the `@prisma/client` into the `npm` project if it is not already present. +3. Inspects the current directory to find a Prisma schema file to process. It will then generate a customized [Prisma Client](https://github.com/prisma/prisma-client-js) for your project. + +#### Prerequisites + +To use the `generate` command, you must add a generator definition in your `schema.prisma` file. The `prisma-client-js` generator, used to generate Prisma Client, can be added by including the following in your `schema.prisma` file: + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +#### Options + +The `generate` command recognizes the following options to modify its behavior: + +| Option | Required | Description | Default | +| ------ | -------- | ----------- | ------- | +| `--schema` | No | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`, `./prisma/schema.prisma` | +| `--watch` | No | The `generate` command will continue to watch the `schema.prisma` file and re-generate Prisma Client on file changes. | + +#### Examples + +**Generate Prisma Client using the default `schema.prisma` path** + +```shell +prisma2 generate +``` + + ✔ Generated Prisma Client to ./node_modules/@prisma/client in 61ms + + You can now start using Prisma Client in your code: + + ``` + import { PrismaClient } from '@prisma/client' + // or const { PrismaClient } = require('@prisma/client') + + const prisma = new PrismaClient() + ``` + + Explore the full API: http://pris.ly/d/client + +**Generate Prisma Client using a non-default `schema.prisma` path** + +```shell +prisma2 generate --schema=./alternative/schema.prisma +``` + +**Continue watching the `schema.prisma` file for changes to automatically re-generate Prisma Client** + +```shell +prisma2 generate --watch +``` +``` +Watching... /home/prismauser/prisma/prisma-play/prisma/schema.prisma + +✔ Generated Prisma Client to ./node_modules/@prisma/client in 45ms +``` + +#### Generated Assets + +The `prisma-client-js` generator creates a customized client for working with your database within the `./node_modules/@prisma/client` directory. + +### introspect + +The `introspect` command connects to your database and adds Prisma models to your Prisma schema that reflect the current database schema. + +To run the `introspect` command, a `schema.prisma` file with a valid [`datasource`](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md#data-sources) must be available. + +> Warning: The command will overwrite the current `schema.prisma` file with the new schema. Any manual changes or customization will be lost. Be sure to back up your current `schema.prisma` file before running `introspect` if it contains important modifications. + +#### Prerequisites + +Before using the `introspect` command, you must define a [valid `datasource`](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md#data-sources) within your `schema.prisma` file. + +For example, the following `datasource` defines an SQLite database file within the current directory: + +```prisma +datasource db { + provider = "sqlite" + url = "file:my-database.db" +} +``` + +#### Options + +The `introspect` command recognizes the following options to modify its behavior: + +| Option | Required | Description | Default | +| ------ | -------- | ----------- | ------- | +| `--schema` | No | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`, `./prisma/schema.prisma` | +| `--print` | No | Prints the created `schema.prisma` to the screen instead of writing it to the filesystem. | + +#### Examples + +**Analyze the database and write its schema to the `schema.prisma` file** + +```shell +prisma2 introspect +``` +``` +Introspecting based on datasource defined in schema.prisma … + +✔ Wrote Prisma data model into schema.prisma in 38ms + +Run prisma2 generate to generate Prisma Client. +``` + +**Specify an alternative `schema.prisma` file to read and write to** + +```shell +prisma2 introspect --schema=./alternative/schema.prisma +``` +``` +Introspecting based on datasource defined in alternative/schema.prisma … + +✔ Wrote Prisma data model into alternative/schema.prisma in 60ms + +Run prisma2 generate to generate Prisma Client. +``` + +**Display the generated `schema.prisma` file instead of writing it to the filesystem** + +```shell +prisma2 introspect --print +``` +```prisma +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "sqlite" + url = "sqlite:./hello-prisma.db" +} + +model User { + email String @unique + name String? + user_id Int @default(autoincrement()) @id + post Post[] + profile Profile[] +} + +model Post { + content String? + post_id Int @default(autoincrement()) @id + title String + author_id User? +} + +model Profile { + bio String? + profile_id Int @default(autoincrement()) @id + user_id User +} +``` + +## Migrations (Experimental) + +> Warning: The `migrate` command is still considered experimental. As such, there are no guarantees about API stability or production-readiness. Access to this command is provided for evaluation and experimentation. To access experimental commands, you must add the `--experimental` flag. + +The `migrate` command creates and manages database migrations. It can be used to create, apply, and rollback database schema updates in a controlled manner. + +The `migrate` command includes a number of subcommands to specify the desired action. + +### migrate save + +Saves a migration that defines the steps necessary to update your current schema. + +#### Prerequisites + +Before using the `migrate save` command, you must define a [valid `datasource`](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md#data-sources) within your `schema.prisma` file. + +For example, the following `datasource` defines an SQLite database file within the current directory: + +```prisma +datasource db { + provider = "sqlite" + url = "file:my-database.db" +} +``` + +#### Options + +The `migrate save` command recognizes the following options to modify its behavior: + +| Option | Required | Description | +| ------ | -------- | ----------- | +| `--experimental` | Yes | Enables use of experimental commands. | +| `-n`, `--name` | No | The name of the migration. If not provided, `migrate save` will prompt you for a name. | +| `-c`, `--create-db` | No | Create the database if it does not exist. | +| `-p`, `--preview` | No | Preview the migration that would be created without writing any changes to the filesystem. | + +#### Generated Assets + +The `migrate save` command generates the following directories and files as necessary: + +* `migrations`: A directory within the current project to store migrations. This directory will be created if it does not exist. +* `migrations/migrate.lock`: A lock file created specifying the current migration applied to the database. This file will be created if it does not exist. +* `migrations/`: A directory for a specific migration. The migration name is derived from the timestamp when it was created followed by a hyphen and the migration name provided by the user. +* `migrations//README.md`: A human-readable description of the migration including metadata like when the migration was created and by who, a list of the actual migration changes and a diff of the changes that are made to the `schema.prisma` file. +* `migrations//schema.prisma`: The schema that will be created if the migration is applied to the project. +* `migrations//steps.json`: An [alternative representation](https://github.com/prisma/specs/tree/master/lift#step) of the migration steps that will be applied. + +#### Examples + +**Create a new migration** + +```shell +prism2 migrate save --experimental +``` + +The command will prompt you for a name for the migration since one was not provided on the command line. After creating the migration, the contents of the generated `schema.prisma` file are displayed. + +**Create a migration with a specific name** + +```shell +prism2 migrate save --name "First migration" --experimental +``` + +**Create the database if it does not already exist** + +```shell +prism2 migrate save --create-db --experimental +``` + +**Preview the migration that would be created by running the `migrate save` command** + +```shell +prism2 migrate save --preview --experimental +``` + +### migrate up + +Migrate the database up to a specific state. + +#### Prerequisites + +Before using the `migrate up` command, you must define a [valid `datasource`](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md#data-sources) within your `schema.prisma` file. + +For example, the following `datasource` defines an SQLite database file within the current directory: + +```prisma +datasource db { + provider = "sqlite" + url = "file:my-database.db" +} +``` + +#### Arguments + +The point to migrate the database up to can be defined in any of the following three ways: + +| Argument | Required | Description | Default | +| -------- | -------- | ---------- | -------- | +| increment | No | Specifies the number of forward migrations to apply. | latest | +| name | No | Specifies where to migrate to using the name of the final migration to apply. | latest | +| timestamp | No | Specifies where to migrate to using the timestamp of the final migration to apply. | latest | + +#### Options + +Additionally, the following options modify the behavior of the `migrate up` command: + +| Option | Required | Description | +| ------ | -------- | ----------- | +| `--experimental` | Yes | Enables use of experimental commands | +| `-c`, `--create-db` | No | Create the database if it does not exist. | +| `-p`, `--preview` | No | Preview the migration that would be created without writing any changes to the filesystem. | + +#### Examples + +**Migrate the database up to the latest available migration** + +```shell +prisma2 migrate up --experimental +``` + +**Apply the next two migrations to the database** + +```shell +prisma2 migrate up 2 --experimental +``` + +**Apply all migrations necessary up to and including a migration by name** + +```shell +prisma2 migrate up "First migration" --experimental +``` + +**Apply all migrations necessary up to and including a migration by timestamp** + +```shell +prisma2 migrate up 20200223181448 --experimental +``` + +**Create the database if it does not already exist before applying the migrations** + +```shell +prisma2 migrate up --create-db --experimental +``` + +**Preview the migration that would be applied by running the `migrate up` command** + +```shell +prisma2 migrate up --preview --experimental +``` + +### migrate down + +Migrate the database down to a specific state. + +#### Prerequisites + +Before using the `migrate down` command, you must define a [valid `datasource`](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md#data-sources) within your `schema.prisma` file. + +For example, the following `datasource` defines an SQLite database file within the current directory: + +```prisma +datasource db { + provider = "sqlite" + url = "file:my-database.db" +} +``` + +#### Arguments + +The point to migrate back to can be defined in any of the following three ways: + +| Argument | Required | Description | Default | +| -------- | -------- | ----------- | ------- | +| decrement | No | Specifies the number of backwards migrations to apply. | 1 | +| name | No | Specifies where to migrate back to using the name of the final migration to apply. | +| timestamp | No | Specifies where to migrate back to using the timestamp of the final migration to apply. | + +#### Options + +Additionally, the following options modify the behavior of the `migrate down` command: + +| Option | Required | Description | +| ------ | -------- | ----------- | +| `--experimental` | Yes | Enables use of experimental commands | +| `-p`, `--preview` | No | Preview the migration that would be created without writing any changes to the filesystem. | + +#### Examples + +**Migrate the database backwards by a single migration** + +```shell +prisma2 migrate down --experimental +``` + +**Migrate the database backwards by two migrations** + +```shell +prisma2 migrate down 2 --experimental +``` +**Migrate backwards through all migrations up to and including a migration by name** + +```shell +prisma2 migrate down "First migration" --experimental +``` + +**Migrate backwards through all migrations up to and including a migration by timestamp** + +```shell +prisma2 migrate down 20200223181448 --experimental +``` + +**Preview the migration that would be applied by running the `migrate down` command** + +```shell +prisma2 migrate down --preview --experimental +``` + +## Studio (Experimental) + +### studio + +> Warning: The `studio` command is still considered experimental. As such, there are no guarantees about API stability or production-readiness. Access to this command is provided for evaluation and experimentation. To access experimental commands, you must add the `--experimental` flag. + +The `studio` command allows you to interact with and manage your data interactively. It does this by starting a local web server with a web app configured with your project's data schema and records. + +#### Prerequisites + +Before using the `studio` command, you must define a [valid `datasource`](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md#data-sources) within your `schema.prisma` file. + +For example, the following `datasource` defines an SQLite database file within the current directory: + +```prisma +datasource db { + provider = "sqlite" + url = "file:my-database.db" +} +``` + +#### Options + +The `studio` command recognizes the following options: + +| Option | Required | Description | Default | +| ------ | -------- | ----------- | -------- | +| `--experimental` | Yes | Enables use of experimental commands | +| `-p`, `--port` | No | The port number to start Studio on. | 5555 | + +#### Examples + +**Start Studio on the default port and open a new browser tab to it** + +```shell +prisma2 studio --experimental +``` + +**Start Studio on a different port and open a new browser tab to it** + +```shell +prisma2 studio --port 7777 --experimental +``` diff --git a/content/03-reference/02-more/01-roadmap.mdx b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx similarity index 67% rename from content/03-reference/02-more/01-roadmap.mdx rename to content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx index e3969d2a81..4b7274431c 100644 --- a/content/03-reference/02-more/01-roadmap.mdx +++ b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx @@ -1,5 +1,5 @@ --- - title: "Roadmap" + title: "Prisma CLI" metaTitle: "" metaDescription: "" --- \ No newline at end of file diff --git a/content/03-reference/02-database-connectors/01-postgresql.mdx b/content/03-reference/02-database-connectors/01-postgresql.mdx new file mode 100644 index 0000000000..2f6848b75c --- /dev/null +++ b/content/03-reference/02-database-connectors/01-postgresql.mdx @@ -0,0 +1,7 @@ +--- +title: "PostgreSQL" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/03-reference/02-database-connectors/02-mysql.mdx b/content/03-reference/02-database-connectors/02-mysql.mdx new file mode 100644 index 0000000000..e91beeb501 --- /dev/null +++ b/content/03-reference/02-database-connectors/02-mysql.mdx @@ -0,0 +1,7 @@ +--- +title: "MySQL" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/03-reference/02-database-connectors/03-sqlite.mdx b/content/03-reference/02-database-connectors/03-sqlite.mdx new file mode 100644 index 0000000000..5fe962e291 --- /dev/null +++ b/content/03-reference/02-database-connectors/03-sqlite.mdx @@ -0,0 +1,7 @@ +--- +title: "SQLite" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/03-reference/02-more/index.mdx b/content/03-reference/02-database-connectors/index.mdx similarity index 100% rename from content/03-reference/02-more/index.mdx rename to content/03-reference/02-database-connectors/index.mdx diff --git a/content/03-reference/03-more/01-editor-setup.mdx b/content/03-reference/03-more/01-editor-setup.mdx new file mode 100644 index 0000000000..1aece765bb --- /dev/null +++ b/content/03-reference/03-more/01-editor-setup.mdx @@ -0,0 +1,7 @@ +--- +title: "Editor setup" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/03-reference/03-more/02-telemetry.mdx b/content/03-reference/03-more/02-telemetry.mdx new file mode 100644 index 0000000000..cd5726df0a --- /dev/null +++ b/content/03-reference/03-more/02-telemetry.mdx @@ -0,0 +1,71 @@ +--- +title: "Telemetry" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +The term **telemetry** refers to the collection of certain usage data to help _improve the quality of a piece of software_. Prisma 2 uses telemetry in two contexts: + +- collecting usage data +- submitting error reports + +This page describes the overall telemetry approach for Prisma 2, what kind of data is collected and how to opt-out of data collection. + +## Why does Prisma collect metrics? + +Telemetry helps us better understand _how many users_ are using our products and _how often_ they are using our products. Unlike many telemetry services, our telemetry implementation is intentionally limited in scope and is actually useful for the developer: + +- **Limited in scope**: We use telemetry to answer one question: how many monthly active developers are using Prisma? +- **Provides value**: Our telemetry service also checks for version updates and offers security notices. + +## When is data collected? + +Data is collected in two scenarios that are described below. + +### Usage data + +Invokations of the `prisma2` CLI sends information to the telemetry server at https://checkpoint.prisma.io. Note that this is only happening at most every 48 hours (i.e., the sending the data to the telemetry server gets pause for 48 hours after any invokation). + +Here is an overview of the data that's being submitted: + +| Field | Attributes | Description | +| -------------: | :--------: | :------------------------------------------------------------------------------------- | +| `product` | _string_ | Name of the product (e.g. `prisma`) | +| `version` | _string_ | Currently installed version of the product (e.g. `1.0.0-rc0`) | +| `arch` | _string_ | Client's operating system architecture (e.g. `amd64`). | +| `os` | _string_ | Client's operating system (e.g. `darwin`). | +| `node_version` | _string_ | Client's node version (e.g. `v12.12.0`). | +| `signature` | _string_ | Random, non-identifiable signature UUID (e.g. `91b014df3-9dda-4a27-a8a7-15474fd899f8`) | +| `user_agent` | _string_ | User agent of the checkpoint client (e.g. `prisma/js-checkpoint`) | +| `timestamp` | _string_ | When the request was made in RFC3339 format (e.g. `2019-12-12T17:45:56Z`) | + +You can opt-out of this behaviour by setting the `CHECKPOINT_DISABLE` environment variable to `1`, e.g.: + +```bash +export CHECKPOINT_DISABLE=1 +``` + +### Error reporting + +During the Preview period, data is potentially collected upon: + +- a crash in the CLI +- a crash or an unexpected error in Prisma Studio + +Before an error report is submitted, there will _always_ be a prompt asking you to confirm or deny the submission of the error report! Error reports are never submitted without your explicit consent! + +## How to opt-out of data collection? + +### Usage data + +You can opt-out of usage data collection by setting the `CHECKPOINT_DISABLE` environment variable to `1`, e.g.: + +```bash +export CHECKPOINT_DISABLE=1 +``` + +### Error reporting + +You can opt-out of data collection by responding to the interactive prompt with _no_. \ No newline at end of file diff --git a/content/03-reference/03-more/index.mdx b/content/03-reference/03-more/index.mdx new file mode 100644 index 0000000000..687633041c --- /dev/null +++ b/content/03-reference/03-more/index.mdx @@ -0,0 +1,6 @@ +--- + title: "More" + metaTitle: "" + metaDescription: "" + staticLink: true +--- \ No newline at end of file diff --git a/content/04-guides/index.mdx b/content/04-guides/index.mdx new file mode 100644 index 0000000000..95431415b4 --- /dev/null +++ b/content/04-guides/index.mdx @@ -0,0 +1,5 @@ +--- + title: "Guides" + metaTitle: "Guides" + metaDescription: "Guides" +--- \ No newline at end of file From c415090c159d4d8c82fba13d823261bf1e5d2cfc Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Fri, 20 Mar 2020 17:11:54 +0100 Subject: [PATCH 07/33] add guides --- .../02-database-connectors/index.mdx | 2 +- .../01-postgresql.mdx | 8 + .../01-setting-up-a-database/02-mysql.mdx | 10 + .../01-setting-up-a-database/03-sqlite.mdx | 7 + .../01-setting-up-a-database/index.mdx | 4 + .../01-postgresql.mdx | 105 +++ .../02-mysql.mdx | 118 +++ .../03-sqlite.mdx | 60 ++ .../02-importing-and-exporting-data/index.mdx | 4 + .../03-primary-keys/01-postgresql.mdx | 8 + .../03-primary-keys/02-mysql.mdx | 10 + .../03-primary-keys/03-sqlite.mdx | 7 + .../03-primary-keys/index.mdx | 4 + .../01-postgresql.mdx | 388 ++++++++++ .../02-mysql.mdx | 412 ++++++++++ .../03-sqlite.mdx | 314 ++++++++ .../index.mdx | 4 + .../05-foreign-keys/01-postgresql.mdx | 271 +++++++ .../05-foreign-keys/02-mysql.mdx | 276 +++++++ .../05-foreign-keys/03-sqlite.mdx | 282 +++++++ .../05-foreign-keys/index.mdx | 4 + .../06-cascading-deletes/01-postgresql.mdx | 708 ++++++++++++++++++ .../06-cascading-deletes/02-mysql.mdx | 541 +++++++++++++ .../06-cascading-deletes/03-sqlite.mdx | 706 +++++++++++++++++ .../06-cascading-deletes/index.mdx | 4 + .../07-data-validation/01-postgresql.mdx | 459 ++++++++++++ .../07-data-validation/02-mysql.mdx | 10 + .../07-data-validation/03-sqlite.mdx | 7 + .../07-data-validation/index.mdx | 4 + .../04-guides/01-database-workflows/index.mdx | 5 + .../01-deploying-to-zeit-now.mdx | 210 ++++++ .../02-deploying-to-aws-lambda.mdx | 8 + .../02-deployment/03-deploying-to-heroku.mdx | 8 + 33 files changed, 4967 insertions(+), 1 deletion(-) create mode 100644 content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx create mode 100644 content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx create mode 100644 content/04-guides/01-database-workflows/01-setting-up-a-database/03-sqlite.mdx create mode 100644 content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx create mode 100644 content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx create mode 100644 content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx create mode 100644 content/04-guides/01-database-workflows/02-importing-and-exporting-data/03-sqlite.mdx create mode 100644 content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx create mode 100644 content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx create mode 100644 content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx create mode 100644 content/04-guides/01-database-workflows/03-primary-keys/03-sqlite.mdx create mode 100644 content/04-guides/01-database-workflows/03-primary-keys/index.mdx create mode 100644 content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/01-postgresql.mdx create mode 100644 content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/02-mysql.mdx create mode 100644 content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/03-sqlite.mdx create mode 100644 content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx create mode 100644 content/04-guides/01-database-workflows/05-foreign-keys/01-postgresql.mdx create mode 100644 content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx create mode 100644 content/04-guides/01-database-workflows/05-foreign-keys/03-sqlite.mdx create mode 100644 content/04-guides/01-database-workflows/05-foreign-keys/index.mdx create mode 100644 content/04-guides/01-database-workflows/06-cascading-deletes/01-postgresql.mdx create mode 100644 content/04-guides/01-database-workflows/06-cascading-deletes/02-mysql.mdx create mode 100644 content/04-guides/01-database-workflows/06-cascading-deletes/03-sqlite.mdx create mode 100644 content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx create mode 100644 content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx create mode 100644 content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx create mode 100644 content/04-guides/01-database-workflows/07-data-validation/03-sqlite.mdx create mode 100644 content/04-guides/01-database-workflows/07-data-validation/index.mdx create mode 100644 content/04-guides/01-database-workflows/index.mdx create mode 100644 content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx create mode 100644 content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx create mode 100644 content/04-guides/02-deployment/03-deploying-to-heroku.mdx diff --git a/content/03-reference/02-database-connectors/index.mdx b/content/03-reference/02-database-connectors/index.mdx index 687633041c..f938528c0a 100644 --- a/content/03-reference/02-database-connectors/index.mdx +++ b/content/03-reference/02-database-connectors/index.mdx @@ -1,5 +1,5 @@ --- - title: "More" + title: "Database connectors" metaTitle: "" metaDescription: "" staticLink: true diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx new file mode 100644 index 0000000000..5f69d12d6d --- /dev/null +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx @@ -0,0 +1,8 @@ +--- +title: "Setting up a database (PostgreSQL)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 + diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx new file mode 100644 index 0000000000..8f4dd93992 --- /dev/null +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx @@ -0,0 +1,10 @@ +--- +title: "Setting up a database (MySQL)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 + + + diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/03-sqlite.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/03-sqlite.mdx new file mode 100644 index 0000000000..f3c247e17f --- /dev/null +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/03-sqlite.mdx @@ -0,0 +1,7 @@ +--- +title: "Setting up a database (SQLite)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx new file mode 100644 index 0000000000..4e80115a96 --- /dev/null +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx @@ -0,0 +1,4 @@ +--- +title: "Setting up a database" +metaTitle: "" +--- \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx new file mode 100644 index 0000000000..d21fb2dea0 --- /dev/null +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx @@ -0,0 +1,105 @@ +--- +title: "Importing and exporting data (PostgreSQL)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This document describes how you can export data from and import data into a PostgreSQL database. You can learn more about this topic in the official [PostgreSQL docs](https://www.postgresql.org/docs/9.1/backup-dump.html). + +## Data export with SQL Dump + +[SQL Dump](https://www.postgresql.org/docs/9.1/backup-dump.html) is a native PostgreSQL utility you can use to export data from your PostgreSQL database. To see all the options for this command, run `pg_dump --help`. + +From the PostgreSQL docs: + +> The idea behind this dump method is to generate a text file with SQL commands that, when fed back to the server, will recreate the database in the same state as it was at the time of the dump. PostgreSQL provides the utility program `pg_dump` for this purpose. +> `pg_dump` is a regular PostgreSQL client application (albeit a particularly clever one). This means that you can perform this backup procedure from any remote host that has access to the database. But remember that pg_dump does not operate with special permissions. In particular, it must have read access to all tables that you want to back up, so in practice you almost always have to run it as a database superuser. + +The command looks like this: + +```psql +pg_dump DB_NAME > OUTPUT_FILE +``` + +You need to replace the `DB_NAME` and `OUTPUT_FILE` placeholders with the respective values for: + +- your **database name** +- the name of the desired **output file** (should end on `.sql`) + +For example, to export data from a local PostgreSQL server from a database called `mydb` into a file called `mydb.sql`, you can use the following command: + +``` +pg_dump mydb > mydb.sql +``` + +If your database schema uses [Object Idenfitifier Types](https://www.postgresql.org/docs/8.1/datatype-oid.html) (OIDs), you'll need to run `pg_dump` with the `--oids` (short: `-o`) option: `pg_dump mydb --oids > mydb.sql`. + +#### Providing database credentials + +You can add the following arguments to specify the location of your PostgreSQL database server: + +| Argument | Default | Env var | Description | +| --- | --- | --- | --- | +| `--host` (short: `-h`) | `localhost` | `PGHOST` | The address of the server's host machine | +| `--port` (short: `-p`) | - | `PGPORT` | The port of the server's host machine where the PostgreSQL server is listening | +To authenticate against the PostgreSQL database server, you can use the following argument: + +| Argument | Default | Env var | Description | +| --- | --- | --- | --- | +| `--username` (short: `-U`) | _your current operating system user name_ | `PGUSER` | The name of the database user. | + +For example, if you want to export data from a PostgerSQL database that has the following [connection string](../core/connectors/postgresql.md): + +``` +postgresql://opnmyfngbknppm:XXX@ec2-46-137-91-216.eu-west-1.compute.amazonaws.com:5432/d50rgmkqi2ipus +``` + +You can use the following `pg_dump` command: + +``` +pg_dump --host ec2-46-137-91-216.eu-west-1.compute.amazonaws.com --port 5432 --user opnmyfngbknppm d50rgmkqi2ipus > heroku_backup.sql +``` + +Note that **this command will trigger a prompt where you need to specify the password** for the provided user. + +#### Controlling the output + +There might be cases where you don't want to dump the _entire_ database, for example you might want to: + +- dump only the actual data but exclude the [DDL](https://www.postgresql.org/docs/8.4/ddl.html) (i.e. the SQL statements that define your database schema like `CREATE TABLE`,...) +- dump only the DDL but exclude the actual data +- exclude a specific PostgreSQL schema +- exclude large files +- exclude specic tables + +Here's an overview of a few command line options you can use in these scenarios: + +| Argument | Default | Description | +| --- | --- | --- | +| `--data-only` (short: `-a`) | `false` | Exclude any [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements and export only data. | +| `--schema-only` (short: `-s`) | `false` | Exclude data and export only [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements. | +| `--blobs` (short: `-b`) | `true` unless either `-schema`, `--table`, or `--schema-only` options are specified | Include binary large objects. | +| `--no-blobs` (short: `-B`) | `false` | Exclude binary large objects. | +| `--table` (short: `-t`) | _includes all tables by default_ | Explicitly specify the names of the tables to be dumped. | +| `--exclude-table` (short: `-T`) | - | Exclude specific tables from the dump. | + +## Importing data from SQL files + +After having used SQL Dump to export your PostgreSQL database as a SQL file, you can restore the state of the database by feeding the SQL file into [`psql`](https://www.postgresql.org/docs/9.3/app-psql.html): + +``` +psql DB_NAME < INPUT_FILE +``` + +You need to replace the `DB_NAME` and `INPUT_FILE` placeholders with the respective values for: + +- your **database name** (a database with hat name must be created beforehand!) +- the name of the target **input file** (likely ends on `.sql`) + +To create the database `DB_NAME` beforehand, you can use the [`template0`](https://www.postgresql.org/docs/9.5/manage-ag-templatedbs.html) (which creates a plain user database that doesn't contain any site-local additions): + +```sql +CREATE DATABASE dbname TEMPLATE template0; +``` \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx new file mode 100644 index 0000000000..cb4c9d9be8 --- /dev/null +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx @@ -0,0 +1,118 @@ +--- +title: "Importing and exporting data (MySQL)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This document describes how you can export data from and import data into a MySQL database. You can learn more about this topic in the official [MySQL docs](https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html). + +## Data export with `mysqldump` + +[`mysqldump`](https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html) is a native MySQL command line utility you can use to export data from your MySQL database. To see all the options for this command, run `mysqldump --help`. + +Note that your [MySQL installation](https://dev.mysql.com/doc/refman/8.0/en/installing.html) comes with `mysqldump` by default, typically contained in `/usr/local/mysql/bin` on Mac OS. This means you can either invoke the command by pointing to that directory `/usr/local/mysql/bin/mysqldump` or [adding it to your `PATH`](https://stackoverflow.com/questions/30990488/how-do-i-install-command-line-mysql-client-on-mac#answer-35338119) so that you can run `mysqldump` without specifying the directory. + +From the MySQL docs: + +> The `mysqldump` client utility performs logical backups, producing a set of SQL statements that can be executed to reproduce the original database object definitions and table data. It dumps one or more MySQL databases for backup or transfer to another SQL server. The `mysqldump` command can also generate output in CSV, other delimited text, or XML format. + +The command looks like this: + +```psql +mysqldump DB_NAME > OUTPUT_FILE +``` + +You need to replace the `DB_NAME` and `OUTPUT_FILE` placeholders with the respective values for: + +- your **database name** +- the name of the desired **output file** (should end on `.sql`) + +For example, to export data from a local MySQL server from a database called `mydb` into a file called `mydb.sql`, you can use the following command: + +``` +mysqldump mydb > mydb.sql +``` + +#### Providing database credentials + +You can add the following arguments to specify the location of your MySQL database server: + +| Argument | Default | Description | +| --- | --- | --- | +| `--host` (short: `-h`) | `localhost` | The address of the server's host machine | +| `--port` (short: `-p`) | - | The port of the server's host machine where the MySQL server is listening | + +To authenticate against the MySQL database server, you can use the following argument: + +| Argument | Default | Description | +| --- | --- | --- | +| `--user` (short: `-u`) | - | The name of the database user. | +| `--password` (short: `-p`) | - | Trigger password prompt. | + +For example, if you want to export data from a MySQL database that has the following [connection string](../core/connectors/mysql.md): + +``` +mysql://opnmyfngbknppm:XXX@ec2-46-137-91-216.eu-west-1.compute.amazonaws.com:5432/d50rgmkqi2ipus +``` + +You can use the following `mysqldump` command: + +``` +mysqldump --host ec2-46-137-91-216.eu-west-1.compute.amazonaws.com --port --user opnmyfngbknppm --password d50rgmkqi2ipus > backup.sql +``` + +Note that **this command will trigger a prompt where you need to specify the password** for the provided user. + +#### Controlling the output + +There might be cases where you don't want to dump the _entire_ database, for example you might want to: + +- dump only the actual data but exclude the [DDL](https://www.postgresql.org/docs/8.4/ddl.html) (i.e. the SQL statements that define your database schema like `CREATE TABLE`,...) +- dump only the DDL but exclude the actual data +- exclude specic tables + +Here's an overview of a few command line options you can use in these scenarios: + +| Argument | Default | Description | +| --- | --- | --- | +| `--no-create-db` (short: `-n`) | `false` | Exclude any [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements and export only data. | +| `--no-data` (short: `-d`) | `false` | Exclude data and export only [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements. | +| `--tables`| _includes all tables by default_ | Explicitly specify the names of the tables to be dumped. | +| `--ignore-table` | - | Exclude specific tables from the dump. | + +## Importing data from SQL files + +After having used `mysqldump` to export your MySQL database as a SQL file, you can restore the state of the database by feeding the SQL file into [`mysql`](https://dev.mysql.com/doc/refman/8.0/en/mysql.html): + +``` +mysql DB_NAME INPUT_FILE +``` + +Note that your [MySQL installation](https://dev.mysql.com/doc/refman/8.0/en/installing.html) comes with `mysql` by default, typically contained in `/usr/local/mysql/bin` on Mac OS. This means you can either invoke the command by pointing to that directory `/usr/local/mysql/bin/mysmysqlqldump` or [adding it to your `PATH`](https://stackoverflow.com/questions/30990488/how-do-i-install-command-line-mysql-client-on-mac#answer-35338119) so that you can run `mysql` without specifying the directory. + +You need to replace the `DB_NAME` and `INPUT_FILE` placeholders with the respective values for: + +- your **database name** (a database with hat name must be created beforehand!) +- the name of the target **input file** (likely ends on `.sql`) + +For example: + +``` +mysql mydb < mydb.sql +``` + +To authenticate, you can use the `--user` and `--password` options discussed above: + +``` +mysql --user root --password mydb < mydb.sql +``` + +To create a database beforehand, you can use the following SQL statement: + +```sql +CREATE DATABASE mydb; +``` + + diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/03-sqlite.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/03-sqlite.mdx new file mode 100644 index 0000000000..914a23d82f --- /dev/null +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/03-sqlite.mdx @@ -0,0 +1,60 @@ +--- +title: "Importing and exporting data (SQLite)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This document describes how you can export data from and import data into a SQLite database. You can learn more about this topic in the official [SQLite docs](https://www.sqlitetutorial.net/sqlite-dump/). + +## Data export with `sqlite3` + +[`sqlite3`](https://www.sqlite.org/cli.html) is a native SQLite command line utility you can use for various workflows accross your SQLite database. To see all the options for this command, run `sqlite3 --help`. Exporting data is typically done with the `.dump` command within the `sqlite3` prompt. + +To export data, you need to enter the `sqlite3` prompt and point it to the location of your SQLite database file (ends on `.db`): + +``` +sqlite3 ./dev.db +``` + +Once you're in the prompt, you can export data as follows: + +``` +sqlite> .output ./backup.sql +sqlite> .dump +sqlite> .exit +``` + +Alternatively, you can export a specific table by adding the table name after the `.dump` command in the prompt. For example the following command only dumps the `users` table: + +``` +sqlite> .output ./backup_users.sql +sqlite> .dump users +sqlite> .exit +``` + +If you want to exclude all data and only export the _database schema_ ([DDL](https://en.wikipedia.org/wiki/Data_definition_language)), you can use `.schema` instead of `.dump`: + +``` +sqlite> .output ./backup_schema.sql +sqlite> .schema +sqlite> .exit +``` + +## Importing data from SQL files + +After having used the `.dump` command insinde the `sqlite3` prompt to export your SQLite database as a SQL file, you can restore the state of the database by feeding the SQL file back into `sqlite3` using the `.read` command. + +Before you can use the `.read` command, you need to enter the `sqlite3` prompt and point it to your SQLite database file: + +``` +sqlite3 ./restore.db +``` + +Now you can import the data from your SQL files as follows: + +``` +.read ./backup.sql +.exit +``` diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx new file mode 100644 index 0000000000..7547dd1f02 --- /dev/null +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx @@ -0,0 +1,4 @@ +--- +title: "Importing and exporting data"" +metaTitle: "" +------ \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx b/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx new file mode 100644 index 0000000000..f77fdc9f9b --- /dev/null +++ b/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx @@ -0,0 +1,8 @@ +--- +title: "Primary keys (PostgreSQL)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 + diff --git a/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx b/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx new file mode 100644 index 0000000000..dda7521ea3 --- /dev/null +++ b/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx @@ -0,0 +1,10 @@ +--- +title: "Primary keys (MySQL)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 + + + diff --git a/content/04-guides/01-database-workflows/03-primary-keys/03-sqlite.mdx b/content/04-guides/01-database-workflows/03-primary-keys/03-sqlite.mdx new file mode 100644 index 0000000000..2cabb744b5 --- /dev/null +++ b/content/04-guides/01-database-workflows/03-primary-keys/03-sqlite.mdx @@ -0,0 +1,7 @@ +--- +title: "Primary keys (SQLite)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 diff --git a/content/04-guides/01-database-workflows/03-primary-keys/index.mdx b/content/04-guides/01-database-workflows/03-primary-keys/index.mdx new file mode 100644 index 0000000000..1eaccdb498 --- /dev/null +++ b/content/04-guides/01-database-workflows/03-primary-keys/index.mdx @@ -0,0 +1,4 @@ +--- +title: "Primary keys" +metaTitle: "" +------ \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/01-postgresql.mdx b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/01-postgresql.mdx new file mode 100644 index 0000000000..be5fd33e3e --- /dev/null +++ b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/01-postgresql.mdx @@ -0,0 +1,388 @@ +--- +title: "Unique constraints and indexes (PostgreSQL)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This page explains how to configure a unique [constraint](https://www.postgresql.org/docs/9.1/ddl-constraints.html#AEN2496) / [index](https://www.postgresql.org/docs/9.1/indexes-unique.html) in your PostgreSQL database. Constraints and indexes are very similar in PostgreSQL (learn more [here](https://medium.com/flatiron-engineering/uniqueness-in-postgresql-constraints-versus-indexes-4cf957a472fd)): When adding a unique constraint to one or more columns, PostgreSQL will always create a corresponding unique index. + +In this guide, you'll always configure unique constraints (which will automatically configure unique indexes as well). + +You can configure unique constraints either on a **single column** or on **multiple columns**. These can be added when you create the table initially (using `CREATE TABLE`) or to an already existing table (using `ALTER TABLE`). This guide covers all four combinations. + +At the end of the guide, you'll introspect your database to reflect the unique constraint in the Prisma schema, then you'll generate Prisma Client and write a simple Node.js script to validate the constraints. + +## Prerequisites + +In order to follow this guide, you need: + +- a [PostgreSQL](https://www.postgresql.org/) database server running +- the [`createdb`](https://www.postgresql.org/docs/9.1/app-createdb.html) command line utility +- the [`psql`](https://www.postgresql.org/docs/10/app-psql.html) command line client for PostgreSQL +- [Node.js](https://nodejs.org/) installed on your machine + +## 1. Create a new database and project directory + +Start by creating a project directory where you can put the files you'll create throughout this guide: + +``` +mkdir unique-demo +cd unique-demo +``` + +Next, make sure that your PostgreSQL database server is running. Then execute the following command in your terminal to create a new database called `UniqueDemo`: + +``` +createdb UniqueDemo +``` + +You can validate that the database was created by running the `\dt` command which lists all tables (_relations_) in your database (right now there are none): + +``` +psql -d UniqueDemo -c "\dt" +``` + +## 2. Create a table with a single-column unique constraint and index + +In this section, you'll **create a new table with a single-column unique constraint** in the `UniqueDemo` database. As mentioned above, this means that PostgreSQL automatically adds a unique index to the same column. + +Create a new file called `single-column-unique.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."User" ( + email TEXT UNIQUE +); +``` + +Now run the SQL statement against your database to create a new table called `User`: + +``` +psql UniqueDemo < single-column-unique.sql +``` + +Congratulations, you just created a table called `User` in the database. The table has one column called `email` on which you defined a unique index. PostgreSQL also automatically added a corresponding unique index (do **not** run this code): + +```sql +CREATE UNIQUE INDEX "User_email_key" ON "User"(email text_ops); +``` + +
Alternative: Define the constraint as a table constraint +
+ +In the code above, you created the unique constraint as a **column constraint**. Alternatively, you can define it as a **table constraint**. There's no practical difference between the two, the alternative is just added for completeness. + +To add the unique constraint as a table constraint, you need to adjust your SQL statement to look as follows: + + +```sql +CREATE TABLE "public"."User" ( + email TEXT, + UNIQUE ("email") +); +``` + +
+ +## 3. Create a table with a multi-column unique constraint and index + +Next, you'll **create a table with a multi-column unique constraint**. This also adds a unique index to the columns with the constraint. + +Create a new file called `multi-column-unique.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."AnotherUser" ( + "firstName" TEXT, + "lastName" TEXT, + UNIQUE (firstName, lastName) +) +``` + +Now run the SQL statement against your database to create a new table called `AnotherUser`: + +``` +psql UniqueDemo < multi-column-unique.sql +``` + +Congratulations, you just created a table called `AnotherUser` in the database. The table has two column called `firstName` and `lastName` on which you defined a unique index. PostgreSQL also automatically added a corresponding unique index (do **not** run this code): + +```sql +CREATE UNIQUE INDEX "AnotherUser_firstname_lastname_key" ON "AnotherUser"(firstname text_ops,lastname text_ops); +``` + +## 4. Adding a single-column unique constraint to an existing table + +In this section, you'll **add a single-column unique constraint to a table that already exists in your database**. To do so, you first need to create a new table and then alter the table to add the constraint. + +Create a new file called `add-single-unique-constraint-later.sql` and add the following code: + +```sql +CREATE TABLE "public"."OneMoreUser" ( + email TEXT +); + +ALTER TABLE "public"."OneMoreUser" ADD CONSTRAINT "OneMoreUser_email_unique_constraint" UNIQUE (email); +``` + +This code contains two SQL statements: + +1. Create a new table called `OneMoreUser` +1. Alter the table to add an unique constraint + +Now run the SQL statements against your database to create a new table called `OneMoreUser`: + +``` +psql UniqueDemo < add-single-unique-constraint-later.sql +``` + +Congratulations, you just created a table called `OneMoreUser` in the database. The table has one column called `email` on which you later added a unique constraint in the second SQL statement. PostgreSQL also automatically added a corresponding unique index (do **not** run this code): + +```sql +CREATE UNIQUE INDEX "OneMoreUser_email_unique_constraint" ON "OneMoreUser"(email text_ops); +``` + +## 5. Adding a multi-column unique constraint to an existing table + +In this section, you'll **add a multi-column unique constraint to a table that already exists in your database**. To do so, you first need to create a new table and then alter the table to add the constraint. + +Create a new file called `add-multi-unique-constraint-later.sql` and add the following code: + +```sql +CREATE TABLE "public"."TheLastUser" ( + "firstName" TEXT, + "lastName" TEXT +); + +ALTER TABLE "public"."TheLastUser" ADD CONSTRAINT "TheLastUser_firstName_lastName_unique_constraint" UNIQUE (firstName, lastName); +``` + +This code contains two SQL statements: + +1. Create a new table called `TheLastUser` +1. Alter the table to add an unique constraint + +Now run the SQL statements against your database to create a new table called `OneMoreUser`: + +``` +psql UniqueDemo < add-multi-unique-constraint-later.sql +``` + +Congratulations, you just created a table called `OneMoreUser` in the database. The table has two columns called `firstName` and `lastName` on which you later added a unique constraint in the second SQL statement. PostgreSQL also automatically added a corresponding unique index (do **not** run this code): + +```sql +CREATE UNIQUE INDEX "TheLastUser_firstName_lastName_unique_constraint" ON "TheLastUser"(firstname text_ops,lastname text_ops); +``` + +### 6. Introspect your database with Prisma + +In the previous sections, you created four tables with unique constraints: + +- The table `User` has a singe-column unique constraint and index on the `email` column +- The table `AnotherUser` has a multi-column unique constraint and index on the `firstName` and `lastName` columns +- The table `OneMoreUser` has a singe-column unique constraint and index on the `email` column +- The table `TheLastUser` has a multi-column unique constraint and index on the `firstName` and `lastName` columns + +In this section you'll introspect your database to generate the Prisma models for these tables. + +To start, set up a new Node.js project and add the `prisma2` CLI as a development dependency: + +``` +npm init -y +npm install prisma2 --save-dev +``` + +In order to introspect your database, you need to tell Prisma how to connect to it. You do so by configuring a `datasource` in your Prisma schema. + +Create a new file called `schema.prisma` and add the following code to it: + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} +``` + +The database connection URL is set via an environment variable. The Prisma CLI automatically supports the [`dotenv`]() format which automatically picks up environment variables defined in a file called `.env`. + +Create a new file called `.env` and set your database connection URL as the `DATABASE_URL` environment variable: + +``` +DATABASE_URL=postgresql://__USER__:__PASSWORD__@__HOST__:__PORT__/UniqueDemo +``` + +In the above code snippet, you need to replace the uppercase placeholders with your own connection details. For example, if your database is running locally it could look like this: + +``` +DATABASE_URL=postgresql://janedoe:mypassword@localhost:5432/UniqueDemo +``` + +With both the `schema.prisma` and `.env` files in place, you can run Prisma's introspection with the following command: + +``` +npx prisma introspect +``` + +This command introspects your database and for each table adds a Prisma model to the Prisma schema: + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model AnotherUser { + firstName String? + lastName String? + + @@unique([firstName, lastName], name: "AnotherUser_firstname_lastname_key") +} + +model OneMoreUser { + email String? @unique +} + +model TheLastUser { + firstName String? + lastName String? + + @@unique([firstName, lastName], name: "TheLastUser_firstName_lastName_unique_constraint") +} + +model User { + email String? @unique +} +``` + +## 7. Generate Prisma Client + +To validate whether the unique constraints work, you'll now generate Prisma Client and send a few sample queries to the database. + +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Run the following command to install and generate Prisma Client in your project: + +``` +npx prisma2 generate +``` + +Now you can use Prisma Client to send database queries in Node.js. + +## 8. Validate the unique constraints in a Node.js script + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const newUser1 = await prisma.user.create({ + data: { + email: "alice@prisma.io" + } + }) + console.log(newUser1) + const newUser2 = await prisma.user.create({ + data: { + email: "alice@prisma.io" + } + }) + console.log(newUser2) +} + +main() +``` + +In this code, you're creating two users with the same `email`, so you're violating the unique constraint that's configured on the `User` table. + +Run the code with this command: + +``` +node index.js +``` + +After `newUser1` gets printed to the console succesfully, the script throws an error indicating that the unique constraint on `email` is violated: + +``` +Invalid `const newUser1 = await prisma.user.create()` invocation in +/Users/janedoe/unique-demo/index.js:6:38 + + 2 + 3 const prisma = new PrismaClient() + 4 + 5 async function main() { +→ 6 const newUser1 = await prisma.user.create(Unique constraint failed on the fields: (`email`) +``` + +To validate the multi-column unique constraint, replace the code in `index.js` with the following: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const newUser1 = await prisma.anotherUser.create({ + data: { + firstName: "Alice", + lastName: "Smith" + } + }) + console.log(newUser1) + const newUser2 = await prisma.anotherUser.create({ + data: { + firstName: "Alice", + lastName: "Smith" + } + }) + console.log(newUser2) +} + +main() +``` + +Run the script again with this command: + +``` +node index.js +``` + +This time, you'll see a similar error message indicating the unique constraint on `firstName` and `lastName` was violated: + +```s +Invalid `newUser2 = await prisma.anotherUser.create()` invocation in +/Users/janedoe/unique-demo/index.js:13:45 + + 9 lastname: "Smith" + 10 } + 11 }) + 12 console.log(newUser1) +→ 13 const newUser2 = await prisma.anotherUser.create(Unique constraint failed on the fields: (`firstname`,`lastname`) +``` + +Note that you can add `NULL` values for these columns without violating the constraints. For example, the following code snippet will **not** fail: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const newUser1 = await prisma.user.create({ data: {} }) + console.log(newUser1) + const newUser2 = await prisma.user.create({ data: {} }) + console.log(newUser2) +} + +main() +``` + +It will create two new records where the `email` is set to `NULL` in the database. \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/02-mysql.mdx b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/02-mysql.mdx new file mode 100644 index 0000000000..083dd5c4e3 --- /dev/null +++ b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/02-mysql.mdx @@ -0,0 +1,412 @@ +--- +title: "Unique constraints and indexes (MySQL)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This page explains how to configure a unique [constraint](https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_unique_constraint) / [index](https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_unique_index) in your MySQL database. Constraints and indexes are very similar in MySQL (learn more [here](https://dba.stackexchange.com/a/147)): When adding a unique constraint to one or more columns, MySQL will always create a corresponding unique index. + +In this guide, you'll always configure unique constraints (which will automatically configure unique indexes as well). + +You can configure unique constraints either on a **single column** or on **multiple columns**. These can be added when you create the table initially (using `CREATE TABLE`) or to an already existing table (using `ALTER TABLE`). This guide covers all four combinations. + +At the end of the guide, you'll introspect your database to reflect the unique constraint in the Prisma schema, then you'll generate Prisma Client and write a simple Node.js script to validate the constraints. + +## Prerequisites + +In order to follow this guide, you need: + +- a [MySQL](https://www.mysql.com/) database server running +- the [`mysql`](https://dev.mysql.com/doc/refman/5.7/en/mysql.html) command line client for MySQL +- [Node.js](https://nodejs.org/) installed on your machine + +## 1. Create a new database and project directory + +Start by creating a project directory where you can put the files you'll create throughout this guide: + +``` +mkdir unique-demo +cd unique-demo +``` + +Next, make sure that your MySQL database server is running. Then execute the following command in your terminal to create a new database called `UniqueDemo`: + +``` +mysql -e 'CREATE DATABASE UniqueDemo;' +``` + +> **Note:** When invoking the `mysql` CLI, you might need to authenticate against your MySQL server. To do so, you need to pass two options to the command: +> +> * `-u __USERNAME__`: The database user +> * `-p`: Enable a password prompt for authentication +> +> Here's a sample invocation for a user called `root` using the above command: +> +> ``` +> mysql -u root -p -e 'CREATE DATABASE UniqueDemo;' +> ``` + + +You can validate that the database was created by running the `SHOW TABLES` command which lists all tables (_relations_) in your database (right now there are none): + +``` +mysql -e 'SHOW TABLES in UniqueDemo;' +``` + +## 2. Create a table with a single-column unique constraint and index + +In this section, you'll **create a new table with a single-column unique constraint** in the `UniqueDemo` database. As mentioned above, this means that MySQL automatically adds a unique index to the same column. + +Create a new file called `single-column-unique.sql` and add the following code to it: + +```sql +CREATE TABLE `UniqueDemo`.`User` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `email` VARCHAR(350) UNIQUE +); +``` + +Now run the SQL statement against your database to create a new table called `User`: + +``` +mysql < single-column-unique.sql +``` + +Congratulations, you just created a table called `User` in the database. The table has an `id` column and a column called `email` on which you defined a unique constraint. MySQL also automatically added a corresponding unique index (do **not** run this code): + +```sql +CREATE UNIQUE INDEX `email` ON `UniqueDemo`.`User`(`email`); +``` + +
Alternative: Define the constraint as a table constraint +
+ +In the code above, you created the unique constraint as a **column constraint**. Alternatively, you can define it as a **table constraint**. There's no practical difference between the two, the alternative is just added for completeness. + +To add the unique constraint as a table constraint, you need to adjust your SQL statement to look as follows: + + +```sql +CREATE TABLE `UniqueDemo`.`User` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `email` VARCHAR(350), + UNIQUE (`email`) +); +``` + +
+ +## 3. Create a table with a multi-column unique constraint and index + +Next, you'll **create a table with a multi-column unique constraint**. This also adds a unique index to the columns with the constraint. + +Create a new file called `multi-column-unique.sql` and add the following code to it: + +```sql +CREATE TABLE `UniqueDemo`.`AnotherUser` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `firstName` VARCHAR(256), + `lastName` VARCHAR(256), + UNIQUE (`firstName`, `lastName`) +); +``` + +Now run the SQL statement against your database to create a new table called `AnotherUser`: + +``` +mysql < multi-column-unique.sql +``` + +Congratulations, you just created a table called `AnotherUser` in the database. The table has an `id` column and two column called `firstName` and `lastName` on which you defined a unique index. MySQL also automatically added a corresponding unique index (do **not** run this code): + +```sql +CREATE UNIQUE INDEX `firstName` ON `UniqueDemo`.`AnotherUser`(`firstName`, `lastName`); +``` + +## 4. Adding a single-column unique constraint to an existing table + +In this section, you'll **add a single-column unique constraint to a table that already exists in your database**. To do so, you first need to create a new table and then alter the table to add the constraint. + +Create a new file called `add-single-unique-constraint-later.sql` and add the following code: + +```sql +CREATE TABLE `UniqueDemo`.`OneMoreUser` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + email VARCHAR(350) +); + +ALTER TABLE `UniqueDemo`.`OneMoreUser` ADD CONSTRAINT `OneMoreUser_email_unique_constraint` UNIQUE (`email`); +``` + +This code contains two SQL statements: + +1. Create a new table called `OneMoreUser` +1. Alter the table to add an unique constraint + +Now run the SQL statements against your database to create a new table called `OneMoreUser`: + +``` +mysql < add-single-unique-constraint-later.sql +``` + +Congratulations, you just created a table called `OneMoreUser` in the database. The table has an `id` column and a column called `email` on which you later added a unique constraint in the second SQL statement. MySQL also automatically added a corresponding unique index (do **not** run this code): + +```sql +CREATE UNIQUE INDEX `OneMoreUser_email_unique_constraint` ON `UniqueDemo`.`OneMoreUser`(`email`); +``` + +## 5. Adding a multi-column unique constraint to an existing table + +In this section, you'll **add a multi-column unique constraint to a table that already exists in your database**. To do so, you first need to create a new table and then alter the table to add the constraint. + +Create a new file called `add-multi-unique-constraint-later.sql` and add the following code: + +```sql +CREATE TABLE `UniqueDemo`.`TheLastUser` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `firstName` VARCHAR(256), + `lastName` VARCHAR(256) +); + +ALTER TABLE `UniqueDemo`.`TheLastUser` ADD CONSTRAINT `TheLastUser_firstName_lastName_unique_constraint` UNIQUE (`firstName`, `lastName`); +``` + +This code contains two SQL statements: + +1. Create a new table called `TheLastUser` +1. Alter the table to add an unique constraint + +Now run the SQL statements against your database to create a new table called `OneMoreUser`: + +``` +mysql < add-multi-unique-constraint-later.sql +``` + +Congratulations, you just created a table called `OneMoreUser` in the database. The table has an `id` column and two columns called `firstName` and `lastName` on which you later added a unique constraint in the second SQL statement. MySQL also automatically added a corresponding unique index (do **not** run this code): + +```sql +CREATE UNIQUE INDEX `TheLastUser_firstName_lastName_unique_constraint` ON `UniqueDemo`.`TheLastUser`(`firstname`, `lastname`); +``` + +### 6. Introspect your database with Prisma + +In the previous sections, you created four tables with unique constraints: + +- The table `User` has a singe-column unique constraint and index on the `email` column +- The table `AnotherUser` has a multi-column unique constraint and index on the `firstName` and `lastName` columns +- The table `OneMoreUser` has a singe-column unique constraint and index on the `email` column +- The table `TheLastUser` has a multi-column unique constraint and index on the `firstName` and `lastName` columns + +In this section you'll introspect your database to generate the Prisma models for these tables. + +To start, set up a new Node.js project and add the `prisma2` CLI as a development dependency: + +``` +npm init -y +npm install prisma2 --save-dev +``` + +In order to introspect your database, you need to tell Prisma how to connect to it. You do so by configuring a `datasource` in your Prisma schema. + +Create a new file called `schema.prisma` and add the following code to it: + +```prisma +datasource mysql { + provider = "mysql" + url = env("DATABASE_URL") +} +``` + +The database connection URL is set via an environment variable. The Prisma CLI automatically supports the [`dotenv`]() format which automatically picks up environment variables defined in a file called `.env`. + +Create a new file called `.env` and set your database connection URL as the `DATABASE_URL` environment variable: + +``` +DATABASE_URL=mysql://__USER__:__PASSWORD__@__HOST__:__PORT__/UniqueDemo +``` + +In the above code snippet, you need to replace the uppercase placeholders with your own connection details. For example, if your database is running locally it could look like this: + +``` +DATABASE_URL=mysql://janedoe:mypassword@localhost:3306/UniqueDemo +``` + +With both the `schema.prisma` and `.env` files in place, you can run Prisma's introspection with the following command: + +``` +npx prisma introspect +``` + +This command introspects your database and for each table adds a Prisma model to the Prisma schema: + +```prisma +datasource mysql { + provider = "mysql" + url = env("DATABASE_URL") +} + +model AnotherUser { + firstName String? + id Int @default(autoincrement()) @id + lastName String? + + @@unique([firstName, lastName], name: "firstName") +} + +model OneMoreUser { + email String? @unique + id Int @default(autoincrement()) @id +} + +model TheLastUser { + firstName String? + id Int @default(autoincrement()) @id + lastName String? + + @@unique([firstName, lastName], name: "TheLastUser_firstName_lastName_unique_constraint") +} + +model User { + email String? @unique + id Int @default(autoincrement()) @id +} +``` + +## 7. Generate Prisma Client + +To validate whether the unique constraints work, you'll now generate Prisma Client and send a few sample queries to the database. + +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Run the following command to install and generate Prisma Client in your project: + +``` +npx prisma generate +``` + +Now you can use Prisma Client to send database queries in Node.js. + +## 8. Validate the unique constraints in a Node.js script + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const newUser1 = await prisma.user.create({ + data: { + email: "alice@prisma.io" + } + }) + console.log(newUser1) + const newUser2 = await prisma.user.create({ + data: { + email: "alice@prisma.io" + } + }) + console.log(newUser2) +} + +main() +``` + +In this code, you're creating two users with the same `email`, so you're violating the unique constraint that's configured on the `User` table. + +Run the code with this command: + +``` +node index.js +``` + +After `newUser1` gets printed to the console succesfully, the script throws an error indicating that the unique constraint on `email` is violated: + +``` +{ email: 'alice@prisma.io', id: 1 } +(node:6883) UnhandledPromiseRejectionWarning: Error: +Invalid `newUser2 = await prisma.user.create()` invocation in +/Users/janedoe/unique-demo/index.js:12:38 + + 8 email: "alice@prisma.io" + 9 } + 10 }) + 11 console.log(newUser1) +→ 12 const newUser2 = await prisma.user.create(Unique constraint failed on the constraint: `email` +``` + +To validate the multi-column unique constraint, replace the code in `index.js` with the following: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const newUser1 = await prisma.anotherUser.create({ + data: { + firstName: "Alice", + lastName: "Smith" + } + }) + console.log(newUser1) + const newUser2 = await prisma.anotherUser.create({ + data: { + firstName: "Alice", + lastName: "Smith" + } + }) + console.log(newUser2) +} + +main() +``` + +Run the script again with this command: + +``` +node index.js +``` + +This time, you'll see a similar error message indicating the unique constraint on `firstName` and `lastName` was violated: + +``` +{ firstName: 'Alice', id: 1, lastName: 'Smith' } +(node:6913) UnhandledPromiseRejectionWarning: Error: +Invalid `newUser2 = await prisma.anotherUser.create()` invocation in +/Users/janedoe/unique-demo/index.js:13:45 + + 9 lastName: "Smith" + 10 } + 11 }) + 12 console.log(newUser1) +→ 13 const newUser2 = await prisma.anotherUser.create(Unique constraint failed on the constraint: `firstName` +``` + +Note that you can add `NULL` values for these columns without violating the constraints. For example, the following code snippet will **not** fail: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const newUser1 = await prisma.user.create({ data: {} }) + console.log(newUser1) + const newUser2 = await prisma.user.create({ data: {} }) + console.log(newUser2) +} + +main() +``` + +It will create two new records where the `email` is set to `NULL` in the database. diff --git a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/03-sqlite.mdx b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/03-sqlite.mdx new file mode 100644 index 0000000000..f515e9b9cd --- /dev/null +++ b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/03-sqlite.mdx @@ -0,0 +1,314 @@ +--- +title: "Unique constraints and indexes (SQLite)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This page explains how to configure a unique [constraint](https://www.sqlite.org/lang_createtable.html#uniqueconst) / [index](https://www.sqlite.org/lang_createindex.html#uniqueidx) in your SQLite database. Constraints and indexes are very similar in SQLite: When adding a unique constraint to one or more columns, SQLite will always create a corresponding unique index. + +In this guide, you'll always configure unique constraints (which will automatically configure unique indexes as well). + +Since [SQLite does not support `ALTER TABLE` statements with the `ADD CONSTRAINT` operation](https://www.sqlite.org/omitted.html), constraints can only be added when you create the table initially (using `CREATE TABLE`). You can configure unique constraints either on a **single column** or on **multiple columns**. This guide covers both of the supported combinations. + +At the end of the guide, you'll introspect your database to reflect the unique constraint in the Prisma schema, then you'll generate Prisma Client and write a simple Node.js script to validate the constraints. + +## Prerequisites + +In order to follow this guide, you need: + +- the [`sqlite3`](https://www.sqlite.org/cli.html) command line client for SQLite +- [Node.js](https://nodejs.org/) installed on your machine + +## 1. Create a new database and project directory + +Start by creating a project directory where you can put the files you'll create throughout this guide: + +``` +mkdir unique-demo +cd unique-demo +``` + +Afterwards, execute the following command in your terminal to create a new database called `UniqueDemo`: + +``` +sqlite3 UniqueDemo.db +``` + +You can validate that the database was created by running the `.tables` command which lists all tables (_relations_) in your database (right now there are none): + +``` +sqlite3 UniqueDemo.db '.tables' +``` + + +## 2. Create a table with a single-column unique constraint and index + +In this section, you'll **create a new table with a single-column unique constraint** in the `UniqueDemo` database. As mentioned above, this means that SQLite automatically adds a unique index to the same column. + +Create a new file called `single-column-unique.sql` and add the following code to it: + +```sql +CREATE TABLE "User" ( + "id" INTEGER PRIMARY KEY, + "email" TEXT UNIQUE +); +``` + +Now run the SQL statement against your database to create a new table called `User`: + +``` +sqlite3 UniqueDemo.db < single-column-unique.sql +``` + +Congratulations, you just created a table called `User` in the database. The table has an `id` column and a column called `email` on which you defined a unique index. SQLite also automatically added a corresponding unique index (do **not** run this code): + +```sql +CREATE UNIQUE INDEX "sqlite_autoindex_User_1" ON "User"("email"); +``` + +
Alternative: Define the constraint as a table constraint +
+ +In the code above, you created the unique constraint as a **column constraint**. Alternatively, you can define it as a **table constraint**. There's no practical difference between the two, the alternative is just added for completeness. + +To add the unique constraint as a table constraint, you need to adjust your SQL statement to look as follows: + + +```sql +CREATE TABLE "User" ( + "id" INTEGER PRIMARY KEY, + "email" TEXT, + UNIQUE ("email") +); +``` + +
+ +## 3. Create a table with a multi-column unique constraint and index + +Next, you'll **create a table with a multi-column unique constraint**. This also adds a unique index to the columns with the constraint. + +Create a new file called `multi-column-unique.sql` and add the following code to it: + +```sql +CREATE TABLE "AnotherUser" ( + "id" INTEGER PRIMARY KEY, + "firstName" TEXT, + "lastName" TEXT, + UNIQUE ("firstName", "lastName") +); +``` + +Now run the SQL statement against your database to create a new table called `AnotherUser`: + +``` +sqlite3 UniqueDemo.db < multi-column-unique.sql +``` + +Congratulations, you just created a table called `AnotherUser` in the database. The table has an `id` column and two column called `firstName` and `lastName` on which you defined a unique index. SQLite also automatically added a corresponding unique index (do **not** run this code): + +```sql +CREATE UNIQUE INDEX "sqlite_autoindex_AnotherUser_1" ON "AnotherUser"("firstName", "lastName"); +``` + +### 4. Introspect your database with Prisma + +In the previous sections, you created two tables with unique constraints: + +- The table `User` has a singe-column unique constraint and index on the `email` column +- The table `AnotherUser` has a multi-column unique constraint and index on the `firstName` and `lastName` columns + +In this section you'll introspect your database to generate the Prisma models for these tables. + +To start, set up a new Node.js project and add the `prisma2` CLI as a development dependency: + +``` +npm init -y +npm install prisma2 --save-dev +``` + +In order to introspect your database, you need to tell Prisma how to connect to it. You do so by configuring a `datasource` in your Prisma schema. + +Create a new file called `schema.prisma` and add the following code to it: + +```prisma +datasource sqlite { + provider = "sqlite" + url = env("DATABASE_URL") +} +``` + +The database connection URL is set via an environment variable. The Prisma CLI automatically supports the [`dotenv`]() format which automatically picks up environment variables defined in a file called `.env`. + +Create a new file called `.env` and set your database connection URL as the `DATABASE_URL` environment variable: + +``` +DATABASE_URL=sqlite:UniqueDemo.db +``` + +With both the `schema.prisma` and `.env` files in place, you can run Prisma's introspection with the following command: + +``` +npx prisma introspect +``` + +This command introspects your database and for each table adds a Prisma model to the Prisma schema: + +```prisma +datasource sqlite { + provider = "sqlite" + url = env("DATABASE_URL") +} + +model User { + email String? @unique + id Int @default(autoincrement()) @id +} + +model AnotherUser { + firstName String? + id Int @default(autoincrement()) @id + lastName String? + + @@unique([firstName, lastName], name: "sqlite_autoindex_AnotherUser_1") +} +``` + +## 5. Generate Prisma Client + +To validate whether the unique constraints work, you'll now generate Prisma Client and send a few sample queries to the database. + +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Run the following command to install and generate Prisma Client in your project: + +``` +npx prisma generate +``` + +Now you can use Prisma Client to send database queries in Node.js. + +## 6. Validate the unique constraints in a Node.js script + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const newUser1 = await prisma.user.create({ + data: { + email: "alice@prisma.io" + } + }) + console.log(newUser1) + const newUser2 = await prisma.user.create({ + data: { + email: "alice@prisma.io" + } + }) + console.log(newUser2) +} + +main() +``` + +In this code, you're creating two users with the same `email`, so you're violating the unique constraint that's configured on the `User` table. + +Run the code with this command: + +``` +node index.js +``` + +After `newUser1` gets printed to the console succesfully, the script throws an error indicating that the unique constraint on `email` is violated: + +``` +{ email: 'alice@prisma.io', id: 1 } +(node:14072) UnhandledPromiseRejectionWarning: Error: +Invalid `newUser2 = await prisma.user.create()` invocation in +/Users/janedoe/unique-demo/index.js:12:38 + + 8 email: "alice@prisma.io" + 9 } + 10 }) + 11 console.log(newUser1) +→ 12 const newUser2 = await prisma.user.create(Unique constraint failed on the fields: (`email`) +``` + +To validate the multi-column unique constraint, replace the code in `index.js` with the following: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const newUser1 = await prisma.anotherUser.create({ + data: { + firstName: "Alice", + lastName: "Smith" + } + }) + console.log(newUser1) + const newUser2 = await prisma.anotherUser.create({ + data: { + firstName: "Alice", + lastName: "Smith" + } + }) + console.log(newUser2) +} + +main() +``` + +Run the script again with this command: + +``` +node index.js +``` + +This time, you'll see a similar error message indicating the unique constraint on `firstName` and `lastName` was violated: + +``` +{ firstName: 'Alice', id: 1, lastName: 'Smith' } +(node:14273) UnhandledPromiseRejectionWarning: Error: +Invalid `newUser2 = await prisma.anotherUser.create()` invocation in +/Users/janedoe/unique-demo/index.js:13:45 + + 9 lastName: "Smith" + 10 } + 11 }) + 12 console.log(newUser1) +→ 13 const newUser2 = await prisma.anotherUser.create(Unique constraint failed on the fields: (`firstName`,`lastName`) +``` + +Note that you can add `NULL` values for these columns without violating the constraints. For example, the following code snippet will **not** fail: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const newUser1 = await prisma.user.create({ data: {} }) + console.log(newUser1) + const newUser2 = await prisma.user.create({ data: {} }) + console.log(newUser2) +} + +main() +``` + +It will create two new records where the `email` is set to `NULL` in the database. diff --git a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx new file mode 100644 index 0000000000..c2c65464d6 --- /dev/null +++ b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx @@ -0,0 +1,4 @@ +--- +title: "Unique constraints and indexes" +metaTitle: "" +------ \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/01-postgresql.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/01-postgresql.mdx new file mode 100644 index 0000000000..b9fb069238 --- /dev/null +++ b/content/04-guides/01-database-workflows/05-foreign-keys/01-postgresql.mdx @@ -0,0 +1,271 @@ +--- +title: "Foreign keys / Relations (PostgreSQL)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This page explains how to configure [foreign key constraints](https://www.postgresql.org/docs/8.2/ddl-constraints.html#DDL-CONSTRAINTS-FK) in your PostgreSQL database. Foreign keys are used to represent _relations_ in your database. + +In this guide, you'll create two tables where one references the other via a foreign key. Foreign keys can be defined on a **single column** or on **multiple columns**. This guide covers both approaches. + +At the end of the guide, you'll introspect your database to reflect the foreign key in the Prisma schema, then you'll generate Prisma Client and write a simple Node.js script to test the foreign key relation. + +## Prerequisites + +In order to follow this guide, you need: + +- a [PostgreSQL](https://www.postgresql.org/) database server running +- the [`createdb`](https://www.postgresql.org/docs/9.1/app-createdb.html) command line utility +- the [`psql`](https://www.postgresql.org/docs/10/app-psql.html) command line client for PostgreSQL +- [Node.js](https://nodejs.org/) installed on your machine + +## 1. Create a new database and project directory + +Start by creating a project directory where you can put the files you'll create throughout this guide: + +``` +mkdir foreign-key-demo +cd foreign-key-demo +``` + +Next, make sure that your PostgreSQL database server is running. Then execute the following command in your terminal to create a new database called `ForeignKeyDemo`: + +``` +createdb ForeignKeyDemo +``` + +You can validate that the database was created by running the `\dt` command which lists all tables (_relations_) in your database (right now there are none): + +``` +psql -d ForeignKeyDemo -c "\dt" +``` + +## 2. Create two tables with a single-column foreign key constraint + +In this section, you'll **create two tables where one references the other via a single-column foreign key** in the `ForeignKeyDemo` database. + +Create a new file called `single-column-foreign-key.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."User" ( + id SERIAL PRIMARY KEY, + name TEXT +); + +CREATE TABLE "public"."Post" ( + id SERIAL PRIMARY KEY, + title TEXT, + author INTEGER, + FOREIGN KEY (author) REFERENCES "public"."User" (id) +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +psql ForeignKeyDemo < single-column-foreign-key.sql +``` + +Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. + +
Alternative: Define the constraint as a column constraint +
+ +In the code above, you created the unique constraint as a **table constraint**. Alternatively, you can define it as a **column constraint**. There's no practical difference between the two, the alternative is just added for completeness. + +To add the foreign key constraint as a column constraint, you need to adjust your SQL statement for creating the `Post` table to look as follows: + +```sql +CREATE TABLE "public"."Post" ( + id SERIAL, + title TEXT, + author INTEGER REFERENCES "public"."User" (id) +); +``` + +
+ +## 3. Create a table with a multi-column foreign key constraint + +In this section, you'll **create two tables where one references the other via a single-column foreign key** in the `ForeignKeyDemo` database. + +Create a new file called `multi-column-foreign-key.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."AnotherUser" ( + id SERIAL PRIMARY KEY, + "firstName" TEXT, + "lastName" TEXT, + UNIQUE ("firstName", "lastName") +); + + +CREATE TABLE "public"."AnotherPost" ( + id SERIAL PRIMARY KEY, + title TEXT, + "authorFirstName" TEXT, + "authorLastName" TEXT, + FOREIGN KEY ("authorFirstName", "authorLastName") REFERENCES "public"."AnotherUser" ("firstName", "lastName") +); +``` + +> **Note**: The quotes are added to the `"firstName"` and `"lastName"` fields to maintain the casing (otherwise PostgreSQL interprets column names as all-lowercase). The `UNIQUE` constraint on `AnotherUser` is needed to be able to reference the columns as foreign keys. + +Now run the SQL statement against your database to create a new table called `AnotherUser`: + +``` +psql ForeignKeyDemo < multi-column-foreign-key.sql +``` + +Congratulations, you just created two tables called `AnotherUser` and `AnotherPost` in the database. The `Post` table references the `User` table via the foreign key defined on the `authorFirstName` and `authorLastName` columns. + +### 4. Introspect your database with Prisma + +In the previous sections, you created two different foreign key constraints using four total tables: + +- The table `Post` has a singe-column foreign key on it's `author` column which points to the `id` field of the `User` table. +- The table `AnotherPost` has a multi-column foreign key on it's `authorFirstName` and `authorLastName` columns which point to the `firstName` and `lastField` columns of the `AnotherUser` table. + +In this section you'll introspect your database to generate the Prisma models for these tables. + +To start, set up a new Node.js project and add the `prisma2` CLI as a development dependency: + +``` +npm init -y +npm install prisma2 --save-dev +``` + +In order to introspect your database, you need to tell Prisma how to connect to it. You do so by configuring a `datasource` in your Prisma schema. + +Create a new file called `schema.prisma` and add the following code to it: + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} +``` + +The database connection URL is set via an environment variable. The Prisma CLI automatically supports the [`dotenv`]() format which automatically picks up environment variables defined in a file called `.env`. + +Create a new file called `.env` and set your database connection URL as the `DATABASE_URL` environment variable: + +``` +DATABASE_URL=postgresql://__USER__:__PASSWORD__@__HOST__:__PORT__/ForeignKeyDemo +``` + +In the above code snippet, you need to replace the uppercase placeholders with your own connection details. For example, if your database is running locally it could look like this: + +``` +DATABASE_URL=postgresql://janedoe:mypassword@localhost:5432/ForeignKeyDemo +``` + +With both the `schema.prisma` and `.env` files in place, you can run Prisma's introspection with the following command: + +``` +npx prisma introspect +``` + +This command introspects your database and for each table adds a Prisma model to the Prisma schema: + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model AnotherPost { + id Int @default(autoincrement()) @id + title String? + anotherUser AnotherUser? @map(["authorFirstName", "authorLastName"]) @relation(references: [firstName, lastName]) +} + +model AnotherUser { + firstName String? + id Int @default(autoincrement()) @id + lastName String? + anotherPost AnotherPost[] + + @@unique([firstName, lastName], name: "AnotherUser_firstName_lastName_key") +} + +model Post { + id Int @default(autoincrement()) @id + title String? + author User? +} + +model User { + id Int @default(autoincrement()) @id + name String? + post Post[] +``` + +## 7. Generate Prisma Client + +To validate whether the foreign key constraints work, you'll now generate Prisma Client and send a few sample queries to the database to test the relations. + +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Run the following command to install and generate Prisma Client in your project: + +``` +npx prisma generate +``` + +Now you can use Prisma Client to send database queries in Node.js. + +## 8. Validate the foreign key constraints in a Node.js script + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.user.create({ + data: { + name: "Alice", + post: { + create: { + title: "Hello World from Alice" + } + } + }, + }) + + const anotherUserWithPost = await prisma.anotherUser.create({ + data: { + firstName: "Bob", + lastName: "Smith", + anotherPost: { + create: { + title: "Hello World from Bob" + } + } + } + }) +} + +main() +``` + +In this code, you're creating two `User` records, each with a related `Post` record. + +Run the code with this command: + +``` +node index.js +``` + +> TODO: The code above did not work at the time of writing this. Needs to be validated once AUMFIDAR is fully finished. diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx new file mode 100644 index 0000000000..a3970e8668 --- /dev/null +++ b/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx @@ -0,0 +1,276 @@ +--- +title: "Foreign keys / Relations (MySQL)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This page explains how to configure [foreign key constraints](https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html) in your MySQL database. Foreign keys are used to represent _relations_ in your database. + +In this guide, you'll create two tables where one references the other via a foreign key. Foreign keys can be defined on a **single column** or on **multiple columns**. This guide covers both approaches. + +At the end of the guide, you'll introspect your database to reflect the foreign key in the Prisma schema, then you'll generate Prisma Client and write a simple Node.js script to test the foreign key relation. + +## Prerequisites + +In order to follow this guide, you need: + +- a [MySQL](https://www.mysql.com/) database server running +- the [`mysql`](https://dev.mysql.com/doc/refman/5.7/en/mysql.html) command line client for MySQL +- [Node.js](https://nodejs.org/) installed on your machine + +## 1. Create a new database and project directory + +Start by creating a project directory where you can put the files you'll create throughout this guide: + +``` +mkdir foreign-key-demo +cd foreign-key-demo +``` + +Next, make sure that your MySQL database server is running. Then execute the following command in your terminal to create a new database called `ForeignKeyDemo`: + +``` +mysql -e 'CREATE DATABASE `ForeignKeyDemo`;' +``` + +You can validate that the database was created by running the `SHOW TABLES` command which lists all tables (_relations_) in your database (right now there are none): + +``` +mysql -e 'SHOW TABLES in `ForeignKeyDemo`;' +``` + +## 2. Create two tables with a single-column foreign key constraint + +In this section, you'll **create two tables where one references the other via a single-column foreign key** in the `ForeignKeyDemo` database. + +Create a new file called `single-column-foreign-key.sql` and add the following code to it: + +```sql +CREATE TABLE `ForeignKeyDemo`.`User` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(256) +); + +CREATE TABLE `ForeignKeyDemo`.`Post` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `title` VARCHAR(256), + `author` INT, + FOREIGN KEY (`author`) REFERENCES `User`(`id`) +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +mysql < single-column-foreign-key.sql +``` + +Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. + +## 3. Create a table with a multi-column foreign key constraint + +In this section, you'll **create two tables where one references the other via a single-column foreign key** in the `ForeignKeyDemo` database. + +Create a new file called `multi-column-foreign-key.sql` and add the following code to it: + +```sql +CREATE TABLE `ForeignKeyDemo`.`AnotherUser` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `firstName` VARCHAR(256), + `lastName` VARCHAR(256), + UNIQUE (`firstName`, `lastName`) +); + +CREATE TABLE `ForeignKeyDemo`.`AnotherPost` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `title` TEXT, + `authorFirstName` VARCHAR(256), + `authorLastName` VARCHAR(256), + FOREIGN KEY (`authorFirstName`, `authorLastName`) REFERENCES `AnotherUser`(`firstName`, `lastName`) +); +``` + +> **Note**: The backticks are added to the `firstName` and `lastName` fields to maintain the casing (otherwise MySQL interprets column names as all-lowercase). The `UNIQUE` constraint on `AnotherUser` is needed to be able to reference the columns as foreign keys. + +Now run the SQL statement against your database to create a new table called `AnotherUser`: + +``` +mysql < multi-column-foreign-key.sql +``` + +Congratulations, you just created two tables called `AnotherUser` and `AnotherPost` in the database. The `Post` table references the `User` table via the foreign key defined on the `authorFirstName` and `authorLastName` columns. + +### 4. Introspect your database with Prisma + +In the previous sections, you created two different foreign key constraints using four total tables: + +- The table `Post` has a singe-column foreign key on it's `author` column which points to the `id` field of the `User` table. +- The table `AnotherPost` has a multi-column foreign key on it's `authorFirstName` and `authorLastName` columns which point to the `firstName` and `lastField` columns of the `AnotherUser` table. + +In this section you'll introspect your database to generate the Prisma models for these tables. + +To start, set up a new Node.js project and add the `prisma2` CLI as a development dependency: + +``` +npm init -y +npm install prisma2 --save-dev +``` + +In order to introspect your database, you need to tell Prisma how to connect to it. You do so by configuring a `datasource` in your Prisma schema. + +Create a new file called `schema.prisma` and add the following code to it: + +```prisma +datasource mysql { + provider = "mysql" + url = env("DATABASE_URL") +} +``` + +The database connection URL is set via an environment variable. The Prisma CLI automatically supports the [`dotenv`]() format which automatically picks up environment variables defined in a file called `.env`. + +Create a new file called `.env` and set your database connection URL as the `DATABASE_URL` environment variable: + +``` +DATABASE_URL=mysql://__USER__:__PASSWORD__@__HOST__:__PORT__/ForeignKeyDemo +``` + +In the above code snippet, you need to replace the uppercase placeholders with your own connection details. For example, if your database is running locally it could look like this: + +``` +DATABASE_URL=mysql://janedoe:mypassword@localhost:3306/ForeignKeyDemo +``` + +With both the `schema.prisma` and `.env` files in place, you can run Prisma's introspection with the following command: + +``` +npx prisma introspect +``` + +This command introspects your database and for each table adds a Prisma model to the Prisma schema: + +```prisma +datasource mysql { + provider = "mysql" + url = env("DATABASE_URL") +} + +model AnotherPost { + id Int @default(autoincrement()) @id + title String? + anotherUser AnotherUser? @map(["authorFirstName", "authorLastName"]) @relation(references: [firstName, lastName]) + + @@index([anotherUser], name: "authorFirstName") +} + +model AnotherUser { + firstName String? + id Int @default(autoincrement()) @id + lastName String? + anotherPost AnotherPost[] + + @@unique([firstName, lastName], name: "firstName") +} + +model Post { + author Int? + id Int @default(autoincrement()) @id + title String? +} + +model User { + id Int @default(autoincrement()) @id + name String? +} +``` + +## 7. Generate Prisma Client + +To validate whether the foreign key constraints work, you'll now generate Prisma Client and send a few sample queries to the database to test the relations. + +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Run the following command to install and generate Prisma Client in your project: + +``` +npx prisma generate +``` + +Now you can use Prisma Client to send database queries in Node.js. + +## 8. Validate the foreign key constraints in a Node.js script + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.user.create({ + data: { + name: "Alice", + post: { + create: { + title: "Hello World from Alice" + } + } + }, + include: { + post: true + } + }) + console.log(userWithPost) + + const anotherUserWithPost = await prisma.anotherUser.create({ + data: { + firstName: "Bob", + lastName: "Smith", + anotherPost: { + create: { + title: "Hello World from Bob" + } + } + }, + include: { + anotherPost: true + } + }) + console.log(anotherUserWithPost) +} + +main() +``` + +In this code, you're creating two `User` records, each with a related `Post` record. + +Run the code with this command: + +``` +node index.js +``` + +The following output indicates that the foreign key constraint is working as intended: + +```js +{ + id: 1, + name: 'Alice', + post: [ { id: 1, title: 'Hello World from Alice' } ] +} +{ + firstName: 'Bob', + id: 1, + lastName: 'Smith', + anotherPost: [ { id: 1, title: 'Hello World from Bob' } ] +} +``` diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/03-sqlite.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/03-sqlite.mdx new file mode 100644 index 0000000000..d46cda0b6b --- /dev/null +++ b/content/04-guides/01-database-workflows/05-foreign-keys/03-sqlite.mdx @@ -0,0 +1,282 @@ +--- +title: "Foreign keys / Relations (SQLite)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This page explains how to configure [foreign key constraints](https://www.sqlite.org/foreignkeys.html) in your SQLite database. Foreign keys are used to represent _relations_ in your database. + +In this guide, you'll create two tables where one references the other via a foreign key. Foreign keys can be defined on a **single column** or on **multiple columns**. This guide covers both approaches. + +At the end of the guide, you'll introspect your database to reflect the foreign key in the Prisma schema, then you'll generate Prisma Client and write a simple Node.js script to test the foreign key relation. + +## Prerequisites + +In order to follow this guide, you need: + +- the [`sqlite3`](https://www.sqlite.org/cli.html) command line client for SQLite +- [Node.js](https://nodejs.org/) installed on your machine + +## 1. Create a new database and project directory + +Start by creating a project directory where you can put the files you'll create throughout this guide: + +``` +mkdir foreign-key-demo +cd foreign-key-demo +``` + +Next, execute the following command in your terminal to create a new database called `ForeignKeyDemo`: + +``` +sqlite3 ForeignKeyDemo.db '.databases' +``` + +You can validate that the database was created by running the `.tables` command which lists all tables (_relations_) in your database (right now there are none): + +``` +sqlite3 ForeignKeyDemo.db '.tables' +``` + +## 2. Create two tables with a single-column foreign key constraint + +In this section, you'll **create two tables where one references the other via a single-column foreign key** in the `ForeignKeyDemo` database. + +Create a new file called `single-column-foreign-key.sql` and add the following code to it: + +```sql +CREATE TABLE "User" ( + "id" INTEGER PRIMARY KEY, + "name" TEXT +); + +CREATE TABLE "Post" ( + "id" INTEGER PRIMARY KEY, + "title" TEXT, + "author" INTEGER, + FOREIGN KEY ("author") REFERENCES "User" ("id") +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +sqlite3 ForeignKeyDemo.db < single-column-foreign-key.sql +``` + +Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. + +
Alternative: Define the constraint as a column constraint +
+ +In the code above, you created the unique constraint as a **table constraint**. Alternatively, you can define it as a **column constraint**. There's no practical difference between the two, the alternative is just added for completeness. + +To add the foreign key constraint as a column constraint, you need to adjust your SQL statement for creating the `Post` table to look as follows: + +```sql +CREATE TABLE "Post" ( + id SERIAL, + title TEXT, + author INTEGER REFERENCES "User"("id") +); +``` + +
+ +## 3. Create a table with a multi-column foreign key constraint + +In this section, you'll **create two tables where one references the other via a single-column foreign key** in the `ForeignKeyDemo` database. + +Create a new file called `multi-column-foreign-key.sql` and add the following code to it: + +```sql +CREATE TABLE "AnotherUser" ( + "id" INTEGER PRIMARY KEY, + "firstName" TEXT, + "lastName" TEXT, + UNIQUE ("firstName", "lastName") +); + + +CREATE TABLE "AnotherPost" ( + "id" INTEGER PRIMARY KEY, + "title" TEXT, + "authorFirstName" TEXT, + "authorLastName" TEXT, + FOREIGN KEY ("authorFirstName", "authorLastName") REFERENCES "AnotherUser"("firstName", "lastName") +); +``` + +> **Note**: The quotes are added to the `"firstName"` and `"lastName"` fields to maintain the casing (otherwise SQLite interprets column names as all-lowercase). The `UNIQUE` constraint on `AnotherUser` is need to be able to reference the columns as foreign keys. + +Now run the SQL statement against your database to create a new table called `AnotherUser`: + +``` +sqlite3 ForeignKeyDemo.db < multi-column-foreign-key.sql +``` + +Congratulations, you just created two tables called `AnotherUser` and `AnotherPost` in the database. The `Post` table references the `User` table via the foreign key defined on the `authorFirstName` and `authorLastName` columns. + +### 4. Introspect your database with Prisma + +In the previous sections, you created two times two tables with foreign key constraints: + +- The table `Post` has a singe-column foreign key on it's `author` column which points to the `id` field of the `User` table. +- The table `AnotherPost` has a multi-column foreign key on it's `authorFirstName` and `authorLastName` columns which point to the `firstName` and `lastField` columns of the `AnotherUser` table. + +In this section you'll introspect your database to generate the Prisma models for these tables. + +To start, set up a new Node.js project and add the `prisma2` CLI as a development dependency: + +``` +npm init -y +npm install prisma2 --save-dev +``` + +In order to introspect your database, you need to tell Prisma how to connect to it. You do so by configuring a `datasource` in your Prisma schema. + +Create a new file called `schema.prisma` and add the following code to it: + +```prisma +datasource sqlite { + provider = "sqlite" + url = env("DATABASE_URL") +} +``` + +The database connection URL is set via an environment variable. The Prisma CLI automatically supports the [`dotenv`]() format which automatically picks up environment variables defined in a file called `.env`. + +Create a new file called `.env` and set your database connection URL as the `DATABASE_URL` environment variable: + +``` +DATABASE_URL=sqlite:ForeignKeyDemo.db +``` + +With both the `schema.prisma` and `.env` files in place, you can run Prisma's introspection with the following command: + +``` +npx prisma introspect +``` + +This command introspects your database and for each table adds a Prisma model to the Prisma schema: + +```prisma +datasource sqlite { + provider = "sqlite" + url = env("DATABASE_URL") +} + +model User { + id Int @default(autoincrement()) @id + name String? + post Post[] +} + +model Post { + id Int @default(autoincrement()) @id + title String? + author User? +} + +model AnotherUser { + firstName String? + id Int @default(autoincrement()) @id + lastName String? + anotherPost AnotherPost[] + + @@unique([firstName, lastName], name: "sqlite_autoindex_AnotherUser_1") +} + +model AnotherPost { + id Int @default(autoincrement()) @id + title String? + anotherUser AnotherUser? @map(["authorFirstName", "authorLastName"]) @relation(references: [firstName, lastName]) +} +``` + +## 7. Generate Prisma Client + +To validate whether the foreign key constraints work, you'll now generate Prisma Client and send a few sample queries to the database to test the relations. + +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Run the following command to install and generate Prisma Client in your project: + +``` +npx prisma2 generate +``` + +Now you can use Prisma Client to send database queries in Node.js. + +## 8. Validate the foreign key constraints in a Node.js script + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.user.create({ + data: { + name: "Alice", + post: { + create: { + title: "Hello World from Alice" + } + } + }, + include: { + post: true + } + }) + console.log(userWithPost) + + const anotherUserWithPost = await prisma.anotherUser.create({ + data: { + firstName: "Bob", + lastName: "Smith", + anotherPost: { + create: { + title: "Hello World from Bob" + } + } + }, + include: { + anotherPost: true + } + }) + console.log(anotherUserWithPost) +} + +main() +``` + +In this code, you're creating two `User` records, each with a related `Post` record. + +Run the code with this command: + +``` +node index.js +``` + +The following output indicates that the foreign key constraint is working as intended: + +```js +{ id: 1, + name: 'Alice', + post: [ { id: 1, title: 'Hello World from Alice' } ] } +{ firstName: 'Bob', + id: 1, + lastName: 'Smith', + anotherPost: [ { id: 1, title: 'Hello World from Bob' } ] } +``` diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx new file mode 100644 index 0000000000..d114bbc945 --- /dev/null +++ b/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx @@ -0,0 +1,4 @@ +--- +title: "Foreign keys" +metaTitle: "" +------ \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/06-cascading-deletes/01-postgresql.mdx b/content/04-guides/01-database-workflows/06-cascading-deletes/01-postgresql.mdx new file mode 100644 index 0000000000..efd707ca51 --- /dev/null +++ b/content/04-guides/01-database-workflows/06-cascading-deletes/01-postgresql.mdx @@ -0,0 +1,708 @@ +--- +title: "Cascading deletes (PostgreSQL)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This page explains how to configure cascading deletes on [foreign key constraints](https://www.postgresql.org/docs/8.2/ddl-constraints.html#DDL-CONSTRAINTS-FK) (relations) in your PostgreSQL database. + +Cascading deletes allow you to configure deletion behavior on relations (e.g. specify a rule like "when a user is deleted, all their posts should be automatically deleted too"). The database will then enforce this behavior when records are deleted. + +There generally are five options for configuring deletion behavior in PostgreSQL (quoting from the [PostgreSQL docs](https://www.postgresql.org/docs/8.2/ddl-constraints.html#DDL-CONSTRAINTS-FK)): + +- `NO ACTION` (default): If any referencing rows still exist when the constraint is checked, an error is raised +- `RESTRICT`: Prevents deletion of a referenced row. The essential difference between these two choices is that `NO ACTION` allows the check to be deferred until later in the transaction, whereas `RESTRICT` does not. +- `CASCADE`: When a referenced row is deleted, row(s) referencing it should be automatically deleted as well. +- `SET NULL`: Causes the referencing columns to be set to `NULL` when the referenced row is deleted. +- `SET DEFAULT`: Causes the referencing columns to be set to their default values when the referenced row is deleted. Note that these do not excuse you from observing any constraints. For example, if an action specifies `SET DEFAULT` but the default value would not satisfy the foreign key, the operation will fail. + +In this guide, you'll create two tables where one references the other via a foreign key and explore the different options for cascading deletes. + +At the end of the guide, you'll introspect your database to reflect the foreign key in the Prisma schema, then you'll generate Prisma Client and write a simple Node.js script to test the deletion behaviors. + +## Prerequisites + +In order to follow this guide, you need: + +- a [PostgreSQL](https://www.postgresql.org/) database server running +- the [`createdb`](https://www.postgresql.org/docs/9.1/app-createdb.html) command line utility +- the [`psql`](https://www.postgresql.org/docs/10/app-psql.html) command line client for PostgreSQL +- the [Node.js](https://nodejs.org/) runtime for JavaScript installed on your machine + +## 1. Create a new database and project directory + +Start by creating a project directory where you can put the files you'll create throughout this guide: + +``` +mkdir cascading-deletes-demo +cd cascading-deletes-demo +``` + +Next, make sure that your PostgreSQL database server is running. Then execute the following command in your terminal to create a new database called `CascadingDeletesDemo`: + +``` +createdb CascadingDeletesDemo +``` + +You can validate that the database was created by running the `\dt` command which lists all tables (_relations_) in your database (right now there are none): + +``` +psql -d CascadingDeletesDemo -c "\dt" +``` + +## 2. Create two tables with a foreign key and `RESTRICT` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key and uses `RESTRICT`** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-restrict.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."User" ( + id SERIAL PRIMARY KEY, + name TEXT +); + +CREATE TABLE "public"."Post" ( + id SERIAL PRIMARY KEY, + title TEXT, + author INTEGER, + FOREIGN KEY (author) REFERENCES "public"."User" (id) ON DELETE RESTRICT +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +psql CascadingDeletesDemo < cascading-deletes-restrict.sql +``` + +Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. + +The deletion bevahior `RESCTRICT` in this case means that it is not possible to delete a `User` record that is referenced `User` record. If you try doing that, the database will throw an error similar to this: + +``` +update or delete on table "User" violates foreign key constraint "Post_author_fkey" on table "Post" +Detail: Key (id)=(1) is still referenced from table "Post". +``` + +
Alternative: Define the constraint as a table constraint +
+ +In the code above, you created the unique constraint as a **table constraint**. Alternatively, you can define it as a **column constraint**. There's no practical difference between the two, the alternative is just added for completeness. + +To add the foreign key constraint as a column constraint, you need to adjust your SQL statement for creating the `Post` table to look as follows: + +```sql +CREATE TABLE "public"."Post" ( + id SERIAL, + title TEXT, + author INTEGER REFERENCES "public"."User" (id) ON DELETE RESTRICT +); +``` + +
+ +## 3. Create two tables with a foreign key and `CASCADE` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key and uses `CASCADE`** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-cascade.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."AnotherUser" ( + id SERIAL PRIMARY KEY, + name TEXT +); + +CREATE TABLE "public"."AnotherPost" ( + id SERIAL PRIMARY KEY, + title TEXT, + author INTEGER, + FOREIGN KEY (author) REFERENCES "public"."AnotherUser" (id) ON DELETE CASCADE +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +psql CascadingDeletesDemo < cascading-deletes-cascade.sql +``` + +Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. + +The deletion bevahior `CASCADE` in this case means that when you delete a `User` record that's referenced by one or more `Post` records, these `Post` records will be deleted as well. + +## 4. Create two tables with a foreign key and `NO ACTION` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key and uses `NO ACTION`** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-no-action.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."OneMoreUser" ( + id SERIAL PRIMARY KEY, + name TEXT +); + +CREATE TABLE "public"."OneMorePost" ( + id SERIAL PRIMARY KEY, + title TEXT, + author INTEGER, + FOREIGN KEY (author) REFERENCES "public"."OneMoreUser" (id) ON DELETE NO ACTION +); +``` + +Note that because `NO ACTION` is the default, you could also omit it: + +```sql +CREATE TABLE "public"."OneMorePost" ( + id SERIAL PRIMARY KEY, + title TEXT, + author INTEGER, + FOREIGN KEY (author) REFERENCES "public"."OneMoreUser" (id) +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +psql CascadingDeletesDemo < cascading-deletes-no-action.sql +``` + +Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. + +The deletion bevahior `NO ACTION` in this case means that it is not possible to delete a `User` record that is referenced `User` record. If you try doing that, the database will throw an error similar to this: + +``` +update or delete on table "User" violates foreign key constraint "Post_author_fkey" on table "Post" +Detail: Key (id)=(1) is still referenced from table "Post". +``` + +## 5. Create two tables with a foreign key and `SET NULL` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key and uses `SET NULL`** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-set-null.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."AlmostTheLastUser" ( + id SERIAL PRIMARY KEY, + name TEXT +); + +CREATE TABLE "public"."AlmostTheLastPost" ( + id SERIAL PRIMARY KEY, + title TEXT, + author INTEGER, + FOREIGN KEY (author) REFERENCES "public"."AlmostTheLastUser" (id) ON DELETE SET NULL +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +psql CascadingDeletesDemo < cascading-deletes-set-null.sql +``` + +Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. + +The deletion bevahior `SET NULL` in this case means that when you delete a `User` record that's referenced by one or more `Post` records, the `author` column on these `Post` records will be set to `NULL` (therefore maintaining the integrity of the data and ensuring that no `Post` records point to non-existing `User` records). + +## 6. Create two tables with a foreign key and `SET DEFAULT` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key and uses `SET DEFAULT`** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-set-default.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."TheLastUser" ( + id SERIAL PRIMARY KEY, + name TEXT +); + +CREATE TABLE "public"."TheLastPost" ( + id SERIAL PRIMARY KEY, + title TEXT, + author INTEGER DEFAULT 42, + FOREIGN KEY (author) REFERENCES "public"."TheLastUser" (id) ON DELETE SET DEFAULT +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +psql CascadingDeletesDemo < cascading-deletes-set-default.sql +``` + +Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. + +The deletion bevahior `SET NULL` in this case means that when you delete a `User` record that's referenced by one or more `Post` records, the `author` column on these `Post` records will be set to the _default_ value of the column. If no default exists, it will be set to `NULL` (in that case, the behavior would be identical to `SET NULL`). In the above table, a contrived example with a default value of `42` is used. If no `User` record with an `id` value of `42` exists though, the operation will fail with a message similar to this: + +``` +insert or update on table "TheLastPost" violates foreign key constraint "TheLastPost_author_fkey" +Detail: Key (author)=(42) is not present in table "TheLastUser". +``` + +Since `Post` records can only ever reference existing `User` records, `SET NULL` also maintains the integrity of the data and ensures that no `Post` records can point to non-existing `User` records. + +## 7. Introspect your database with Prisma + +In the previous sections, you created five times two tables with foreign key constraints: + +- The table `Post` uses `RESTRICT` behavior on the foreign key column `author` which points to the `User` table +- The table `AnotherPost` uses `CASCADE` behavior on the foreign key column `author` which points to the `User` table +- The table `OneMorePost` uses `NO ACTION` behavior on the foreign key column `author` which points to the `User` table +- The table `AlmostTheLastPost` uses `SET NULL` behavior on the foreign key column `author` which points to the `User` table +- The table `TheLastPost` uses `SET DEFAULT` behavior on the foreign key column `author` which points to the `User` table + +In this section you'll introspect your database to generate the Prisma models for these tables. + +To start, set up a new Node.js project and add the `prisma2` CLI as a development dependency: + +``` +npm init -y +npm install prisma2 --save-dev +``` + +In order to introspect your database, you need to tell Prisma how to connect to it. You do so by configuring a `datasource` in your Prisma schema. + +Create a new file called `schema.prisma` and add the following code to it: + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} +``` + +The database connection URL is set via an environment variable. The Prisma CLI automatically supports the [`dotenv`]() format which automatically picks up environment variables defined in a file called `.env`. + +Create a new file called `.env` and set your database connection URL as the `DATABASE_URL` environment variable: + +``` +DATABASE_URL=postgresql://__USER__:__PASSWORD__@__HOST__:__PORT__/CascadingDeletesDemo +``` + +In the above code snippet, you need to replace the uppercase placeholders with your own connection details. For example, if your database is running locally it could look like this: + +``` +DATABASE_URL=postgresql://janedoe:mypassword@localhost:5432/CascadingDeletesDemo +``` + +With both the `schema.prisma` and `.env` files in place, you can run Prisma's introspection with the following command: + +``` +npx prisma introspect +``` + +This command introspects your database and for each table adds a Prisma model to the Prisma schema: + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model AlmostTheLastPost { + id Int @default(autoincrement()) @id + title String? + author AlmostTheLastUser? +} + +model AlmostTheLastUser { + id Int @default(autoincrement()) @id + name String? + almostTheLastPost AlmostTheLastPost[] +} + +model AnotherPost { + id Int @default(autoincrement()) @id + title String? + author AnotherUser? +} + +model AnotherUser { + id Int @default(autoincrement()) @id + name String? + anotherPost AnotherPost[] +} + +model OneMorePost { + id Int @default(autoincrement()) @id + title String? + author OneMoreUser? +} + +model OneMoreUser { + id Int @default(autoincrement()) @id + name String? + oneMorePost OneMorePost[] +} + +model Post { + id Int @default(autoincrement()) @id + title String? + author User? +} + +model TheLastPost { + id Int @default(autoincrement()) @id + title String? + author TheLastUser? +} + +model TheLastUser { + id Int @default(autoincrement()) @id + name String? + theLastPost TheLastPost[] +} + +model User { + id Int @default(autoincrement()) @id + name String? + post Post[] +} +``` + +> **Note**: Deletion behaviors for relations are not yet supported in the Prisma schema so you don't see them anywhere. The behavior will still be enforced by the database though since that's where you configured it. + +## 8. Generate Prisma Client + +To validate whether the foreign key constraints work, you'll now generate Prisma Client and send a few sample queries to the database to test the relations. + +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Run the following command to install and generate Prisma Client in your project: + +``` +npx prisma2 generate +``` + +Now you can use Prisma Client to send database queries in Node.js. + +## 9. Validate the deletion behavior in a Node.js script + +### 9.1. Validating `RESTRICT` + +The `RESTRICT` keyword prevents deletion of a referenced row. So, when trying to delete a `User` record that is reference by a `Post` record, the query will fail. + +To test the `RESTRICT` behavior, you need to access the `User` and `Post` tables. + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.user.create({ + data: { + name: 'Alice', + post: { + create: { title: 'Hello World' }, + }, + }, + }) + + try { + const deletedUser = await prisma.user.delete({ + where: { id: userWithPost.id }, + }) + } catch (e) { + console.log(e) + } +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The script will throw an exception when invoking `prisma.user.delete(...)`. The error will look similar to this: + +``` +PrismaClientUnknownRequestError: +Invalid `const deletedUser = await prisma.user.delete()` invocation in +/Users/nikolasburk/Desktop/unique/cascasing-deletes-demo/index.js:16:49 + + 12 }, + 13 }) + 14 + 15 try { +→ 16 const deletedUser = await prisma.user.delete(Error occurred during query execution: +ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: Db, cause: Some(DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState("23503"), message: "update or delete on table \"User\" violates foreign key constraint \"Post_author_fkey\" on table \"Post\"", detail: Some("Key (id)=(8) is still referenced from table \"Post\"."), hint: None, position: None, where_: None, schema: Some("public"), table: Some("Post"), column: None, datatype: None, constraint: Some("Post_author_fkey"), file: Some("ri_triggers.c"), line: Some(3280), routine: Some("ri_ReportViolation") }) }) }) + at PrismaClientFetcher.request (/Users/nikolasburk/Desktop/unique/cascasing-deletes-demo/node_modules/@prisma/client/index.js:89:17) + at processTicksAndRejections (internal/process/task_queues.js:89:5) +``` + +### 9.2. Validating `CASCADE` + +The `CASCADE` keyword ensures that when a referenced row is deleted, all the rows that are referencing it get deleted as well. So, when trying to delete an `AnotherUser` record that is referenced by one or more `AnotherPost` records, these `AnotherPost` records will be deleted too. + +To test the `CASCADE` behavior, you need to access the `AnotherUser` and `AnotherPost` tables. + +Open the `index.js` file and replace its contents with the following code: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.anotherUser.create({ + data: { + name: 'Alice', + anotherPost: { + create: { title: 'Hello World' }, + }, + }, + }) + + const allUsers1 = await prisma.anotherUser.findMany() + const allPosts1 = await prisma.anotherPost.findMany() + + console.log(`Before deleting the \`User\` record there are ${allUsers1.length} users and ${allPosts1.length} posts.`) + + + const deletedUser = await prisma.anotherUser.delete({ + where: { id: userWithPost.id }, + }) + + const allUsers2 = await prisma.anotherUser.findMany() + const allPosts2 = await prisma.anotherPost.findMany() + + console.log(`After deleting the \`User\` record there are ${allUsers2.length} users and ${allPosts2.length} posts.`) +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The console output will look similar to this: + +``` +Before deleting the `User` record there are 1 users and 1 posts. +After deleting the `User` record there are 0 users and 0 posts. +``` + +### 9.3. Validating `NO ACTION` + + +The `NO ACTION` keyword prevents deletion of a referenced row. So, when trying to delete a `OneMoreUser` record that is reference by a `OneMorePost` record, the query will fail. + +To test the `NO ACTION` behavior, you need to access the `OneMoreUser` and `OneMorePost` tables. + +Open the `index.js` file and replace its contents with the following code: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.oneMoreUser.create({ + data: { + name: 'Alice', + oneMorePost: { + create: { title: 'Hello World' }, + }, + }, + }) + + try { + const deletedUser = await prisma.oneMoreUser.delete({ + where: { id: userWithPost.id }, + }) + } catch (e) { + console.log(e) + } +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The script will throw an exception when invoking `prisma.user.delete(...)`. The error will look similar to this: + +``` +PrismaClientUnknownRequestError: +Invalid `const deletedUser = await prisma.oneMoreUser.delete()` invocation in +/Users/nikolasburk/Desktop/unique/cascasing-deletes-demo/index.js:16:56 + + 12 }, + 13 }) + 14 + 15 try { +→ 16 const deletedUser = await prisma.oneMoreUser.delete(Error occurred during query execution: +ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: Db, cause: Some(DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState("23503"), message: "update or delete on table \"OneMoreUser\" violates foreign key constraint \"OneMorePost_author_fkey\" on table \"OneMorePost\"", detail: Some("Key (id)=(2) is still referenced from table \"OneMorePost\"."), hint: None, position: None, where_: None, schema: Some("public"), table: Some("OneMorePost"), column: None, datatype: None, constraint: Some("OneMorePost_author_fkey"), file: Some("ri_triggers.c"), line: Some(3280), routine: Some("ri_ReportViolation") }) }) }) + at PrismaClientFetcher.request (/Users/nikolasburk/Desktop/unique/cascasing-deletes-demo/node_modules/@prisma/client/index.js:89:17) + at processTicksAndRejections (internal/process/task_queues.js:89:5) +``` + +### 9.4. Validating `SET NULL` + +The `SET NULL` keyword ensures that when a referenced row is deleted, all the rows that are referencing it reset their foreign key to `NULL`. So, when deleting an `AlmostTheLastUser` record that is referenced by one or more `AlmostTheLastPost` records, these `AlmostTheLastPost` records will reset their `author` fields to `NULL`. + +To test the `SET NULL` behavior, you need to access the `AlmostTheLastUser` and `AlmostTheLastPost` tables. + +Open the `index.js` file and replace its contents with the following code: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.almostTheLastUser.create({ + data: { + name: 'Alice', + almostTheLastPost: { + create: { title: 'Hello World' }, + }, + }, + include: { + almostTheLastPost: true + } + }) + + const postBefore = await prisma.almostTheLastPost.findOne({ + where: { id: userWithPost.almostTheLastPost[0].id }, + include: { author: true } + }) + + console.log(`Before deleting the \`User\` record, the \`Post\` record looks as follows:\n${JSON.stringify(postBefore)}`) + + const deletedUser = await prisma.almostTheLastUser.delete({ + where: { id: userWithPost.id }, + }) + + const postAfter = await prisma.almostTheLastPost.findOne({ + where: { id: postBefore.id }, + include: { author: true } + }) + + console.log(`After deleting the \`User\` record, the \`Post\` record looks as follows:\n${JSON.stringify(postAfter)}`) +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The console output will look similar to this: + +``` +$ node index.js +Before deleting the `User` record, the `Post` record looks as follows: +{"id":6,"title":"Hello World","author":{"id":6,"name":"Alice"}} +After deleting the `User` record, the `Post` record looks as follows: +{"id":6,"title":"Hello World","author":null} +``` + +### 9.5. Validating `SET DEFAULT` + +The `SET DEFAULT` keyword ensures that when a referenced row is deleted, all the rows that are referencing it set their foreign key to their default value (if there's no default value defined, it resets the foreign key to `NULL`). So, when deleting an `TheLastUser` record that is referenced by one or more `TheLastPost` records, these `TheLastPost` records will reset their `author` fields to `NULL`. + +To test the `SET DEFAULT` behavior, you need to access the `TheLastUser` and `TheLastPost` tables. + +Open the `index.js` file and replace its contents with the following code: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.theLastUser.create({ + data: { + name: 'Alice', + theLastPost: { + create: { title: 'Hello World' }, + }, + }, + include: { + theLastPost: true + } + }) + + const postBefore = await prisma.theLastPost.findOne({ + where: { + author: { id: userWithPost.posts[0].id } + } + }) + + console.log(`Before deleting the \`User\` record, the \`Post\` record looks as follows:\n${JSON.stringify(postBefore)}`) + + const deletedUser = await prisma.theLastUser.delete({ + where: { id: userWithPost.id }, + }) + + const postAfter = await prisma.theLastPost.findOne({ + where: { id: postBefore.id } + }) + + console.log(`After deleting the \`User\` record, the \`Post\` record looks as follows:\n${JSON.stringify(postAfter)}`) +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +If you run this command and there's no `User` record in the database with an `id` of `42`, the script is going to fail with the following error: + +``` +Before deleting the `User` record, the `Post` record looks as follows: +{"id":4,"title":"Hello World","author":{"id":5,"name":"Alice"}} +(node:43705) UnhandledPromiseRejectionWarning: Error: +Invalid `prisma.theLastUsers.delete()` invocation in +/Users/nikolasburk/Desktop/unique/cascasing-deletes-demo/index.js:25:54 + +Error occurred during query execution: +ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: Db, cause: Some(DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState("23503"), message: "insert or update on table \"TheLastPost\" violates foreign key constraint \"TheLastPost_author_fkey\"", detail: Some("Key (author)=(42) is not present in table \"TheLastUser\"."), hint: None, position: None, where_: None, schema: Some("public"), table: Some("TheLastPost"), column: None, datatype: None, constraint: Some("TheLastPost_author_fkey"), file: Some("ri_triggers.c"), line: Some(3266), routine: Some("ri_ReportViolation") }) }) }) + at PrismaClientFetcher.request (/Users/nikolasburk/Desktop/unique/cascasing-deletes-demo/node_modules/@prisma/client/index.js:89:17) + at processTicksAndRejections (internal/process/task_queues.js:89:5) +(node:43705) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) +(node:43705) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. +``` + +If there is a `User` record with an `id` of `42`, the output will look similar to this: + +``` +$ node index.js +Before deleting the `User` record, the `Post` record looks as follows: +{"id":6,"title":"Hello World","author":{"id":6,"name":"Alice"}} +After deleting the `User` record, the `Post` record looks as follows: +{"id":6,"title":"Hello World","author":{"id":42,"name":"Bob"}} +``` diff --git a/content/04-guides/01-database-workflows/06-cascading-deletes/02-mysql.mdx b/content/04-guides/01-database-workflows/06-cascading-deletes/02-mysql.mdx new file mode 100644 index 0000000000..38edfd9d8e --- /dev/null +++ b/content/04-guides/01-database-workflows/06-cascading-deletes/02-mysql.mdx @@ -0,0 +1,541 @@ +--- +title: "Cascading deletes (MySQL)" +metaTitle: "" +metaDescription: "" +--- + +## Overviews + +This page explains how to configure cascading deletes on [foreign key constraints](https://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html) (relations) in your MySQL database. + +Cascading deletes allow you to configure deletion behavior on relations (e.g. specify a rule like "when a user is deleted, all their posts should be automatically deleted too"). The database will then enforce this behavior when records are deleted. + +There generally are five options for configuring deletion behavior in MySQL (paraphrasing from the [MySQL docs](https://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html#foreign-key-referential-actions)): + +- `RESTRICT` (default): Prevents deleting the parent table if a child table references it. +- `NO ACTION`: Same as `RESTRICT` in MySQL +- `CASCADE`: When a row is deleted in the parent table, row(s) referencing it should be automatically deleted as well. +- `SET NULL`: Causes the referencing columns to be set to `NULL` when the referenced row is deleted. +- `SET DEFAULT`: Causes the referencing columns to be set to their default values when the referenced row is deleted. While this is recognized by MySQL, [InnoDB](https://dev.mysql.com/doc/refman/5.7/en/innodb-storage-engine.html) (the most common MySQL database engine) and [NDB](https://dev.mysql.com/doc/refman/5.7/en/mysql-cluster.html) do not allow the `SET DEFAULT` action. + +In this guide, you'll create two tables where one references the other via a foreign key and explore the different options for cascading deletes. + +At the end of the guide, you'll introspect your database to reflect the foreign key in the Prisma schema, then you'll generate Prisma Client and write a simple Node.js script to test the deletion behaviors. + +## Prerequisites + +In order to follow this guide, you need: + +- a [MySQL](https://dev.mysql.com/doc/refman/5.7/en/mysqld.html) database server running +- the [`mysql`](https://dev.mysql.com/doc/refman/5.7/en/mysql.html) command line client for MySQL +- the [Node.js](https://nodejs.org/) runtime for JavaScript installed on your machine + +## 1. Create a new database and project directory + +Start by creating a project directory where you can put the files you'll create throughout this guide: + +``` +mkdir cascading-deletes-demo +cd cascading-deletes-demo +``` + +Next, make sure that your MySQL database server is running. Then execute the following command in your terminal to create a new database called `CascadingDeletesDemo`: + +``` +mysql -e 'CREATE DATABASE `CascadingDeletesDemo`' +``` + +You can validate that the database was created by running the `SHOW TABLES` command which lists all tables (_relations_) in your database (right now there are none): + +``` +mysql -e 'SHOW TABLES in `CascadingDeletesDemo`;' +``` + +## 2. Create two tables with a foreign key and `RESTRICT` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key with the `RESTRICT` action** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-restrict.sql` and add the following code to it: + +```sql +CREATE TABLE `CascadingDeletesDemo`.`User` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(256) +); + +CREATE TABLE `CascadingDeletesDemo`.`Post` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `title` VARCHAR(256), + `author` INT, + FOREIGN KEY (`author`) REFERENCES `CascadingDeletesDemo`.`User`(`id`) ON DELETE RESTRICT +); +``` + +Note that because `RESTRICT` is the default, you could also omit it: + +```sql +CREATE TABLE `CascadingDeletesDemo`.`Post` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `title` VARCHAR(256), + `author` INT, + FOREIGN KEY (`author`) REFERENCES `CascadingDeletesDemo`.`User`(`id`) +); +``` + +Alternatively, you could also use `NO ACTION` since `RESTRICT` and `NO ACTION` are identical in MySQL: + +```sql +CREATE TABLE `CascadingDeletesDemo`.`Post` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `title` VARCHAR(256), + `author` INT, + FOREIGN KEY (`author`) REFERENCES `CascadingDeletesDemo`.`User`(`id`) ON DELETE NO ACTION +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +mysql < cascading-deletes-restrict.sql +``` + +Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. + +The deletion action `RESTRICT` in this case means that it is not possible to delete a `User` record that is referenced by a `Post` record. If you try doing that, the database will throw an error similar to this: + +``` +update or delete on table "User" violates foreign key constraint "Post_author_fkey" on table "Post" +Detail: Key (id)=(1) is still referenced from table "Post". +``` + +
Alternative: Define the constraint as a column constraint +
+ +In the code above, you created the unique constraint as a **table constraint**. Alternatively, you can define it as a **column constraint**. There's no practical difference between the two, the alternative is just added for completeness. + +To add the foreign key constraint as a column constraint, you need to adjust your SQL statement for creating the `Post` table to look as follows: + +```sql +CREATE TABLE `CascadingDeletesDemo`.`Post` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `title` VARCHAR(256), + `author` INT, + author INT REFERENCES `CascadingDeletesDemo`.`User`(`id`) ON DELETE RESTRICT +); +``` + +
+ +## 3. Create two tables with a foreign key and `CASCADE` deletion action + +In this section, you'll **create two tables where one references the other via a foreign key with the `CASCADE` action** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-cascade.sql` and add the following code to it: + +```sql +CREATE TABLE `CascadingDeletesDemo`.`AnotherUser` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(256) +); + +CREATE TABLE `CascadingDeletesDemo`.`AnotherPost` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `title` VARCHAR(256), + `author` INT, + FOREIGN KEY (`author`) REFERENCES `CascadingDeletesDemo`.`AnotherUser` (`id`) ON DELETE CASCADE +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +mysql < cascading-deletes-cascade.sql +``` + +Congratulations, you just created two tables called `AnotherUser` and `AnotherPost` in the database. The `AnotherPost` table references the `AnotherUser` table via the foreign key defined on the `author` column. + +The deletion action `CASCADE` in this case means that when you delete a `AnotherUser` record that's referenced by one or more `AnotherPost` records, these `AnotherPost` records will be deleted as well. + +## 4. Create two tables with a foreign key and `SET NULL` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key with the `SET NULL` action** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-set-null.sql` and add the following code to it: + +```sql +CREATE TABLE `CascadingDeletesDemo`.`AlmostTheLastUser` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(256) +); + +CREATE TABLE `CascadingDeletesDemo`.`AlmostTheLastPost` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `title` VARCHAR(256), + `author` INT, + FOREIGN KEY (`author`) REFERENCES `CascadingDeletesDemo`.`AlmostTheLastUser`(`id`) ON DELETE SET NULL +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +mysql < cascading-deletes-set-null.sql +``` + +Congratulations, you just created two tables called `AlmostTheLastUser` and `AlmostTheLastPost` in the database. The `AlmostTheLastPost` table references the `AlmostTheLastUser` table via the foreign key defined on the `author` column. + +The deletion behavior `SET NULL` in this case means that when you delete an `AlmostTheLastUser` record that's referenced by one or more `AlmostTheLastPost` records, the `author` column on these `AlmostTheLastPost` records will be set to `NULL` (therefore maintaining the integrity of the data and ensuring that no `AlmostTheLastPost` records point to non-existing `AlmostTheLastUser` records). + +## 5. Create two tables with a foreign key and `SET DEFAULT` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key with the `SET DEFAULT` action** in the `CascadingDeletesDemo` database. Remember, InnoDB, the most common MySQL database engine does not allow the `SET DEFAULT`. We'll show this example for use with other database types, but delete the tables once we're done to clean our example up. + +Create a new file called `cascading-deletes-set-default.sql` and add the following code to it: + +```sql +CREATE TABLE `CascadingDeletesDemo`.`TheLastUser` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(256) +); + +CREATE TABLE `CascadingDeletesDemo`.`TheLastPost` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `title` VARCHAR(256), + `author` INT DEFAULT 42, + FOREIGN KEY (`author`) REFERENCES `CascadingDeletesDemo`.`TheLastUser` (`id`) ON DELETE SET DEFAULT +); +``` + +Now run the SQL statement against your database to try to create the two tables: + +``` +mysql < cascading-deletes-set-default.sql +``` + +MySQL will raise the following error because InnoDB does not allow the `SET DEFAULT` action: + +``` +ERROR 1215 (HY000) at line 6: Cannot add foreign key constraint +``` + +When used on tables using a different database engine, the `TheLastPost` table would reference the `TheLastUser` table via the foreign key defined on the `author` column. + +If you were using a different database engine, the deletion behavior `SET DEFAULT` would mean that when you delete a `TheLastUser` record that's referenced by one or more `TheLastPost` records, the `author` column on these `TheLastPost` records would be set to the _default_ value of the column. + +If no default exists, it would be set to `NULL` (in that case, the behavior would be identical to `SET NULL`). In the above table, a contrived example with a default value of `42` is used. If no `TheLastUser` record with an `id` value of `42` exists though, the operation would fail with a message similar to this: + +``` +insert or update on table "TheLastPost" violates foreign key constraint "TheLastPost_author_fkey" +Detail: Key (author)=(42) is not present in table "TheLastUser". +``` + +Since `TheLastPost` records would only ever reference existing `TheLastUser` records, `SET NULL` also maintains the integrity of the data and ensures that no `TheLastPost` records can point to non-existing `TheLastUser` records. + +Since you were not able to create a `TheLastPost` table with the `SET DEFAULT` constraint, you can clean up the `TheLastUser` table: + +``` +mysql -e 'DROP TABLE `CascadingDeletesDemo`.`TheLastUser`;' +``` + +### 6. Introspect your database with Prisma + +In the previous sections, you created two tables with foreign key constraints for each of the following three scenarios: + +- The table `Post` uses `RESTRICT` action on the foreign key column `author` which points to the `User` table. This is identical to the default behavior and the `NO ACTION` behavior. +- The table `AnotherPost` uses `CASCADE` action on the foreign key column `author` which points to the `AnotherUser` table. +- The table `AlmostTheLastPost` uses `SET NULL` action on the foreign key column `author` which points to the `AlmostTheLastUser` table + +In addition to the above behavior, you also confirmed that the default database engine (InnoDB) does not allow for the `SET DEFAULT` action on delete. The relationship between the following tables was not allowed: + +- The table `TheLastPost` used the `SET DEFAULT` action on the foreign key column `author` which pointed to the `TheLastUser` table + +In this section you'll introspect your database to generate the Prisma models for these tables. + +To start, set up a new Node.js project and add the `prisma2` CLI as a development dependency: + +``` +npm init -y +npm install prisma2 --save-dev +``` + +In order to introspect your database, you need to tell Prisma how to connect to it. You do so by configuring a `datasource` in your Prisma schema. + +Create a new file called `schema.prisma` and add the following code to it: + +```prisma +datasource mysql { + provider = "mysql" + url = env("DATABASE_URL") +} +``` + +The database connection URL is set via an environment variable. The Prisma CLI automatically supports the [`dotenv`](https://www.npmjs.com/package/dotenv) format which automatically picks up environment variables defined in a file called `.env`. + +Create a new file called `.env` and set your database connection URL as the `DATABASE_URL` environment variable: + +``` +DATABASE_URL=mysql://__USER__:__PASSWORD__@__HOST__:__PORT__/CascadingDeletesDemo +``` + +In the above code snippet, you need to replace the uppercase placeholders with your own connection details. For example, if your database is running locally it could look like this: + +``` +DATABASE_URL=mysql://janedoe:mypassword@localhost:3306/CascadingDeletesDemo +``` + +With both the `schema.prisma` and `.env` files in place, you can run Prisma's introspection with the following command: + +``` +npx prisma introspect +``` + +This command introspects your database and for each table adds a Prisma model to the Prisma schema: + +```prisma +datasource mysql { + provider = "mysql" + url = env("DATABASE_URL") +} + +model AlmostTheLastPost { + id Int @default(autoincrement()) @id + title String? + author AlmostTheLastUser? + + @@index([author], name: "author") +} + +model AlmostTheLastUser { + id Int @default(autoincrement()) @id + name String? + almostTheLastPost AlmostTheLastPost[] +} + +model AnotherPost { + id Int @default(autoincrement()) @id + title String? + author AnotherUser? + + @@index([author], name: "author") +} + +model AnotherUser { + id Int @default(autoincrement()) @id + name String? + anotherPost AnotherPost[] +} + +model Post { + id Int @default(autoincrement()) @id + title String? + author User? + + @@index([author], name: "author") +} + +model User { + id Int @default(autoincrement()) @id + name String? + post Post[] +} +``` + +> **Note**: Deletion behaviors for relations are not yet supported in the Prisma schema so you don't see them anywhere. The behavior will still be enforced by the database though since that's where you configured it. + +## 7. Generate Prisma Client + +To validate whether the foreign key constraints work, you'll now generate Prisma Client and send a few sample queries to the database to test the relations. + +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Run the following command to install and generate Prisma Client in your project: + +``` +npx prisma generate +``` + +Now you can use Prisma Client to send database queries in Node.js. + +## 8. Validate the deletion behavior in a Node.js script + +### 8.1. Validating `RESTRICT` + +The `RESTRICT` keyword prevents deletion of a referenced row. So, when trying to delete a `User` record that is reference by a `Post` record, the query will fail. + +To test the `RESTRICT` behavior, you need to access the `User` and `Post` tables. + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.user.create({ + data: { + name: 'Alice', + post: { + create: { title: 'Hello World' }, + }, + }, + }) + + try { + const deletedUser = await prisma.user.delete({ + where: { id: userWithPost.id }, + }) + } catch (e) { + console.log(e) + } +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The script will throw an exception when invoking `prisma.user.delete(...)`. The error will look similar to this: + +``` +PrismaClientUnknownRequestError: +Invalid `const deletedUser = await prisma.user.delete()` invocation in +/Users/janedoe/cascasing-deletes-demo/index.js:16:49 + + 12 }, + 13 }) + 14 + 15 try { +→ 16 const deletedUser = await prisma.user.delete(Error occurred during query execution: +ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Server(ServerError { code: 1451, message: "Cannot delete or update a parent row: a foreign key constraint fails (`CascadingDeletesDemo`.`Post`, CONSTRAINT `Post_ibfk_1` FOREIGN KEY (`author`) REFERENCES `User` (`id`))", state: "23000" })) }) + at PrismaClientFetcher.request (/home/justin/cascading-deletes-demo/node_modules/@prisma/client/index.js:89:17) + at processTicksAndRejections (internal/process/task_queues.js:97:5) +``` + +### 8.2. Validating `CASCADE` + +The `CASCADE` keyword ensures that when a referenced row is deleted, all the rows that are referencing it get deleted as well. So, when trying to delete an `AnotherUser` record that is referenced by one or more `AnotherPost` records, these `AnotherPost` records will be deleted too. + +To test the `CASCADE` behavior, you need to access the `AnotherUser` and `AnotherPost` tables. + +Open the `index.js` file and replace its contents with the following code: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.anotherUser.create({ + data: { + name: 'Alice', + anotherPost: { + create: { title: 'Hello World' }, + }, + }, + }) + + const allUsers1 = await prisma.anotherUser.findMany() + const allPosts1 = await prisma.anotherPost.findMany() + + console.log(`Before deleting the \`User\` record there are ${allUsers1.length} users and ${allPosts1.length} posts.`) + + + const deletedUser = await prisma.anotherUser.delete({ + where: { id: userWithPost.id }, + }) + + const allUsers2 = await prisma.anotherUser.findMany() + const allPosts2 = await prisma.anotherPost.findMany() + + console.log(`After deleting the \`User\` record there are ${allUsers2.length} users and ${allPosts2.length} posts.`) +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The console output will look similar to this: + +``` +Before deleting the `User` record there are 1 users and 1 posts. +After deleting the `User` record there are 0 users and 0 posts. +``` + +### 8.3. Validating `SET NULL` + +The `SET NULL` keyword ensures that when a referenced row is deleted, all the rows that are referencing it reset their foreign key to `NULL`. So, when deleting an `AlmostTheLastUser` record that is referenced by one or more `AlmostTheLastPost` records, these `AlmostTheLastPost` records will reset their `author` fields to `NULL`. + +To test the `SET NULL` behavior, you need to access the `AlmostTheLastUser` and `AlmostTheLastPost` tables. + +Open the `index.js` file and replace its contents with the following code: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.almostTheLastUser.create({ + data: { + name: 'Alice', + almostTheLastPost: { + create: { title: 'Hello World' }, + }, + }, + include: { + almostTheLastPost: true + } + }) + + const postBefore = await prisma.almostTheLastPost.findOne({ + where: { id: userWithPost.almostTheLastPost[0].id }, + include: { author: true } + }) + + console.log(`Before deleting the \`almostTheLastUser\` record, the \`almostTheLastPost\` record looks as follows:\n${JSON.stringify(postBefore)}`) + + const deletedUser = await prisma.almostTheLastUser.delete({ + where: { id: userWithPost.id }, + }) + + const postAfter = await prisma.almostTheLastPost.findOne({ + where: { id: postBefore.id }, + include: { author: true } + }) + + console.log(`After deleting the \`almostTheLastUser\` record, the \`almostTheLastPost\` record looks as follows:\n${JSON.stringify(postAfter)}`) +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The console output will look similar to this: + +``` +Before deleting the `almostTheLastUser` record, the `almostTheLastPost` record looks as follows: +{"id":6,"title":"Hello World","author":{"id":6,"name":"Alice"}} +After deleting the `almostTheLastUser` record, the `almostTheLastPost` record looks as follows: +{"id":6,"title":"Hello World","author":null} +``` diff --git a/content/04-guides/01-database-workflows/06-cascading-deletes/03-sqlite.mdx b/content/04-guides/01-database-workflows/06-cascading-deletes/03-sqlite.mdx new file mode 100644 index 0000000000..0c18d14470 --- /dev/null +++ b/content/04-guides/01-database-workflows/06-cascading-deletes/03-sqlite.mdx @@ -0,0 +1,706 @@ +--- +title: "Cascading deletes (SQLite)" +metaTitle: "" +metaDescription: "" +--- + +## Overviews + +This page explains how to configure cascading deletes on [foreign key constraints](https://www.sqlite.org/foreignkeys.html#fk_actions) (relations) in your PostgreSQL database. + +Cascading deletes allow you to configure deletion behavior on relations (e.g. specify a rule like "when a user is deleted, all their posts should be automatically deleted too"). The database will then enforce this behavior when records are deleted. + +There generally are five options for configuring deletion behavior in SQLite (paraphrasing from the [SQLite docs](https://www.sqlite.org/foreignkeys.html#fk_actions)): + +- `NO ACTION` (default): If any referencing rows still exist when the constraint is checked, an error is raised +- `RESTRICT`: Prevents deletion of a referenced row. The difference between these two choices is that `NO ACTION` allows the check to be deferred until later in the transaction, whereas `RESTRICT` does not. +- `SET NULL`: Causes the referencing columns to be set to `NULL` when the referenced row is deleted. +- `SET DEFAULT`: Causes the referencing columns to be set to their default values when the referenced row is deleted. Note that these do not excuse you from observing any constraints. For example, if an action specifies `SET DEFAULT` but the default value would not satisfy the foreign key, the operation will fail. +- `CASCADE`: When a referenced row is deleted, row(s) referencing it should be automatically deleted as well. + +In this guide, you'll create two tables where one references the other via a foreign key and explore the different options for cascading deletes. + +At the end of the guide, you'll introspect your database to reflect the foreign key in the Prisma schema, then you'll generate Prisma Client and write a simple Node.js script to test the deletion behaviors. + +## Prerequisites + +In order to follow this guide, you need: + +- the [`sqlite3`](https://www.sqlite.org/cli.html) command line client for SQLite +- the [Node.js](https://nodejs.org/) runtime for JavaScript installed on your machine + +## 1. Create a new database and project directory + +Start by creating a project directory where you can put the files you'll create throughout this guide: + +``` +mkdir cascading-deletes-demo +cd cascading-deletes-demo +``` + +Next, make sure that your PostgreSQL database server is running. Then execute the following command in your terminal to create a new database called `CascadingDeletesDemo`: + +``` +sqlite3 CascadingDeletesDemo.db '.databases' +``` + +You can validate that the database was created by running the `\dt` command which lists all tables (_relations_) in your database (right now there are none): + +``` +sqlite3 CascadingDeletesDemo.db '.tables' +``` + +## 2. Create two tables with a foreign key and `RESTRICT` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key with the `RESTRICT` action** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-restrict.sql` and add the following code to it: + +```sql +CREATE TABLE "User" ( + "id" INTEGER PRIMARY KEY, + "name" TEXT +); + +CREATE TABLE "Post" ( + "id" INTEGER PRIMARY KEY, + "title" TEXT, + "author" INTEGER, + FOREIGN KEY ("author") REFERENCES "User" ("id") ON DELETE RESTRICT +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +sqlite3 CascadingDeletesDemo.db < cascading-deletes-restrict.sql +``` + +Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. + +The deletion behavior `RESCTRICT` in this case means that it is not possible to delete a `User` record that is referenced `User` record. If you try doing that, the database will throw an error similar to this: + +``` +update or delete on table "User" violates foreign key constraint "Post_author_fkey" on table "Post" +Detail: Key (id)=(1) is still referenced from table "Post". +``` + +
Alternative: Define the constraint as a column constraint +
+ +In the code above, you created the unique constraint as a **table constraint**. Alternatively, you can define it as a **column constraint**. There's no practical difference between the two, the alternative is just added for completeness. + +To add the foreign key constraint as a column constraint, you need to adjust your SQL statement for creating the `Post` table to look as follows: + +```sql +CREATE TABLE "Post" ( + "id" INTEGER PRIMARY KEY, + "title" TEXT, + "author" INTEGER REFERENCES "User" ("id") ON DELETE RESTRICT +); +``` + +
+ +## 3. Create two tables with a foreign key and `CASCADE` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key with the `CASCADE` action** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-cascade.sql` and add the following code to it: + +```sql +CREATE TABLE "AnotherUser" ( + "id" INTEGER PRIMARY KEY, + "name" TEXT +); + +CREATE TABLE "AnotherPost" ( + "id" INTEGER PRIMARY KEY, + "title" TEXT, + "author" INTEGER, + FOREIGN KEY ("author") REFERENCES "AnotherUser" ("id") ON DELETE CASCADE +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +sqlite3 CascadingDeletesDemo.db < cascading-deletes-cascade.sql +``` + +Congratulations, you just created two tables called `AnotherUser` and `AnotherPost` in the database. The `AnotherPost` table references the `AnotherUser` table via the foreign key defined on the `author` column. + +The deletion behavior `CASCADE` in this case means that when you delete an `AnotherUser` record that's referenced by one or more `AnotherPost` records, these `AnotherPost` records will be deleted as well. + +## 4. Create two tables with a foreign key and `NO ACTION` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key with the `NO ACTION` action** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-no-action.sql` and add the following code to it: + +```sql +CREATE TABLE "OneMoreUser" ( + "id" INTEGER PRIMARY KEY, + "name" TEXT +); + +CREATE TABLE "OneMorePost" ( + "id" INTEGER PRIMARY KEY, + "title" TEXT, + "author" INTEGER, + FOREIGN KEY ("author") REFERENCES "OneMoreUser" ("id") ON DELETE NO ACTION +); +``` + +Note that because `NO ACTION` is the default, you could also omit it: + +```sql +CREATE TABLE "OneMorePost" ( + "id" INTEGER PRIMARY KEY, + "title" TEXT, + "author" INTEGER, + FOREIGN KEY ("author") REFERENCES "OneMoreUser" ("id") +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +sqlite3 CascadingDeletesDemo.db < cascading-deletes-no-action.sql +``` + +Congratulations, you just created two tables called `OneMoreUser` and `OneMorePost` in the database. The `OneMorePost` table references the `OneMoreUser` table via the foreign key defined on the `author` column. + +The deletion behavior `NO ACTION` in this case means that it is not possible to delete a `OneMoreUser` record that is referenced `OneMoreUser` record. If you try doing that, the database will throw an error similar to this: + +``` +update or delete on table "User" violates foreign key constraint "Post_author_fkey" on table "Post" +Detail: Key (id)=(1) is still referenced from table "Post". +``` + +## 5. Create two tables with a foreign key and `SET NULL` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key with the `SET NULL` action** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-set-null.sql` and add the following code to it: + +```sql +CREATE TABLE "AlmostTheLastUser" ( + "id" INTEGER PRIMARY KEY, + "name" TEXT +); + +CREATE TABLE "AlmostTheLastPost" ( + "id" INTEGER PRIMARY KEY, + "title" TEXT, + "author" INTEGER, + FOREIGN KEY ("author") REFERENCES "AlmostTheLastUser" ("id") ON DELETE SET NULL +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +sqlite3 CascadingDeletesDemo.db < cascading-deletes-set-null.sql +``` + +Congratulations, you just created two tables called `AlmostTheLastUser` and `AlmostTheLastPost` in the database. The `AlmostTheLastPost` table references the `AlmostTheLastUser` table via the foreign key defined on the `author` column. + +The deletion behavior `SET NULL` in this case means that when you delete a `AlmostTheLastUser` record that's referenced by one or more `AlmostTheLastPost` records, the `author` column on these `AlmostTheLastPost` records will be set to `NULL` (therefore maintaining the integrity of the data and ensuring that no `AlmostTheLastPost` records point to non-existing `AlmostTheLastUser` records). + +## 6. Create two tables with a foreign key and `SET DEFAULT` deletion behavior + +In this section, you'll **create two tables where one references the other via a foreign key with the `SET DEFAULT` action** in the `CascadingDeletesDemo` database. + +Create a new file called `cascading-deletes-set-default.sql` and add the following code to it: + +```sql +CREATE TABLE "TheLastUser" ( + "id" INTEGER PRIMARY KEY, + "name" TEXT +); + +CREATE TABLE "TheLastPost" ( + "id" INTEGER PRIMARY KEY, + "title" TEXT, + "author" INTEGER DEFAULT 42, + FOREIGN KEY ("author") REFERENCES "TheLastUser" ("id") ON DELETE SET DEFAULT +); +``` + +Now run the SQL statement against your database to create the two tables: + +``` +sqlite3 CascadingDeletesDemo.db < cascading-deletes-set-default.sql +``` + +Congratulations, you just created two tables called `TheLastUser` and `TheLastPost` in the database. The `TheLastPost` table references the `TheLastUser` table via the foreign key defined on the `author` column. + +The deletion behavior `SET NULL` in this case means that when you delete a `TheLastUser` record that's referenced by one or more `TheLastPost` records, the `author` column on these `TheLastPost` records will be set to the _default_ value of the column. + +If no default exists, it will be set to `NULL` (in that case, the behavior would be identical to `SET NULL`). In the above table, a contrived example with a default value of `42` is used. If no `TheLastUser` record with an `id` value of `42` exists though, the operation will fail with a message similar to this: + +``` +insert or update on table "TheLastPost" violates foreign key constraint "TheLastPost_author_fkey" +Detail: Key (author)=(42) is not present in table "TheLastUser". +``` + +Since `TheLastPost` records can only ever reference existing `TheLastUser` records, `SET NULL` also maintains the integrity of the data and ensures that no `TheLastPost` records can point to non-existing `TheLastUser` records. + +## 7. Introspect your database with Prisma + +In the previous sections, you created five times two tables with foreign key constraints: + +- The table `Post` uses `RESTRICT` action on the foreign key column `author` which points to the `User` table +- The table `AnotherPost` uses `CASCADE` action on the foreign key column `author` which points to the `AnotherUser` table +- The table `OneMorePost` uses `NO ACTION` action on the foreign key column `author` which points to the `OneMoreUser` table +- The table `AlmostTheLastPost` uses `SET NULL` action on the foreign key column `author` which points to the `AlmostTheLastUser` table +- The table `TheLastPost` uses `SET DEFAULT` action on the foreign key column `author` which points to the `TheLastUser` table + +In this section you'll introspect your database to generate the Prisma models for these tables. + +To start, set up a new Node.js project and add the `prisma2` CLI as a development dependency: + +``` +npm init -y +npm install prisma2 --save-dev +``` + +In order to introspect your database, you need to tell Prisma how to connect to it. You do so by configuring a `datasource` in your Prisma schema. + +Create a new file called `schema.prisma` and add the following code to it: + +```prisma +datasource sqlite { + provider = "sqlite" + url = env("DATABASE_URL") +} +``` + +The database connection URL is set via an environment variable. The Prisma CLI automatically supports the [`dotenv`](https://www.npmjs.com/package/dotenv) format which automatically picks up environment variables defined in a file called `.env`. + +Create a new file called `.env` and set your database connection URL as the `DATABASE_URL` environment variable: + +``` +DATABASE_URL=sqlite:CascadingDeletesDemo.db +``` + +With both the `schema.prisma` and `.env` files in place, you can run Prisma's introspection with the following command: + +``` +npx prisma introspect +``` + +This command introspects your database and for each table adds a Prisma model to the Prisma schema: + +```prisma +datasource sqlite { + provider = "sqlite" + url = env("DATABASE_URL") +} + +model User { + id Int @default(autoincrement()) @id + name String? + post Post[] +} + +model Post { + id Int @default(autoincrement()) @id + title String? + author User? +} + +model anotherUser { + id Int @default(autoincrement()) @id + name String? + anotherPost anotherPost[] +} + +model anotherPost { + id Int @default(autoincrement()) @id + title String? + author anotherUser? +} + +model OneMoreUser { + id Int @default(autoincrement()) @id + name String? + oneMorePost OneMorePost[] +} + +model OneMorePost { + id Int @default(autoincrement()) @id + title String? + author OneMoreUser? +} + +model AlmostTheLastUser { + id Int @default(autoincrement()) @id + name String? + almostTheLastPost AlmostTheLastPost[] +} + +model AlmostTheLastPost { + id Int @default(autoincrement()) @id + title String? + author AlmostTheLastUser? +} + +model TheLastUser { + id Int @default(autoincrement()) @id + name String? + theLastPost TheLastPost[] +} + +model TheLastPost { + id Int @default(autoincrement()) @id + title String? + author TheLastUser? +} +``` + +> **Note**: Deletion behaviors for relations are not yet supported in the Prisma schema so you don't see them anywhere. The behavior will still be enforced by the database though since that's where you configured it. + +## 8. Generate Prisma Client + +To validate whether the foreign key constraints work, you'll now generate Prisma Client and send a few sample queries to the database to test the relations. + +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): + +```prisma +generator client { + provider = "prisma-client-js" +} +``` + +Run the following command to install and generate Prisma Client in your project: + +``` +npx prisma2 generate +``` + +Now you can use Prisma Client to send database queries in Node.js. + +## 9. Validate the deletion behavior in a Node.js script + +### 9.1. Validating `RESTRICT` + +The `RESTRICT` keyword prevents deletion of a referenced row. So, when trying to delete a `User` record that is reference by a `Post` record, the query will fail. + +To test the `RESTRICT` behavior, you need to access the `User` and `Post` tables. + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.user.create({ + data: { + name: 'Alice', + post: { + create: { title: 'Hello World' }, + }, + }, + }) + + try { + const deletedUser = await prisma.user.delete({ + where: { id: userWithPost.id }, + }) + } catch (e) { + console.log(e) + } +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The script will throw an exception when invoking `prisma.user.delete(...)`. The error will look similar to this: + +``` +PrismaClientUnknownRequestError: +Invalid `const deletedUser = await prisma.user.delete()` invocation in +/Users/janedoe/cascasing-deletes-demo/index.js:16:49 + + 12 }, + 13 }) + 14 + 15 try { +→ 16 const deletedUser = await prisma.user.delete(Error occurred during query execution: +ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(SqliteFailure(Error { code: ConstraintViolation, extended_code: 1811 }, Some("FOREIGN KEY constraint failed"))) }) + at PrismaClientFetcher.request (/home/justin/prisma/cascading-deletes-demo/node_modules/@prisma/client/index.js:89:17) + at process._tickCallback (internal/process/next_tick.js:68:7) +``` + +### 9.2. Validating `CASCADE` + +The `CASCADE` keyword ensures that when a referenced row is deleted, all the rows that are referencing it get deleted as well. So, when trying to delete an `AnotherUser` record that is referenced by one or more `AnotherPost` records, these `AnotherPost` records will be deleted too. + +To test the `CASCADE` behavior, you need to access the `AnotherUser` and `AnotherPost` tables. + +Open the `index.js` file and replace its contents with the following code: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.anotherUser.create({ + data: { + name: 'Alice', + anotherPost: { + create: { title: 'Hello World' }, + }, + }, + }) + + const allUsers1 = await prisma.anotherUser.findMany() + const allPosts1 = await prisma.anotherPost.findMany() + + console.log(`Before deleting the \`AnotherUser\` record there are ${allUsers1.length} users and ${allPosts1.length} posts.`) + + + const deletedUser = await prisma.anotherUser.delete({ + where: { id: userWithPost.id }, + }) + + const allUsers2 = await prisma.anotherUser.findMany() + const allPosts2 = await prisma.anotherPost.findMany() + + console.log(`After deleting the \`AnotherUser\` record there are ${allUsers2.length} users and ${allPosts2.length} posts.`) +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The console output will look similar to this: + +``` +Before deleting the `User` record there are 1 users and 1 posts. +After deleting the `User` record there are 0 users and 0 posts. +``` + +### 9.3. Validating `NO ACTION` + + +The `NO ACTION` keyword prevents deletion of a referenced row. So, when trying to delete a `OneMoreUser` record that is reference by a `OneMorePost` record, the query will fail. + +To test the `NO ACTION` behavior, you need to access the `OneMoreUser` and `OneMorePost` tables. + +Open the `index.js` file and replace its contents with the following code: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.oneMoreUser.create({ + data: { + name: 'Alice', + oneMorePost: { + create: { title: 'Hello World' }, + }, + }, + }) + + try { + const deletedUser = await prisma.oneMoreUser.delete({ + where: { id: userWithPost.id }, + }) + } catch (e) { + console.log(e) + } +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The script will throw an exception when invoking `prisma.user.delete(...)`. The error will look similar to this: + +``` +PrismaClientUnknownRequestError: +Invalid `const deletedUser = await prisma.oneMoreUser.delete()` invocation in +/Users/janedoe/cascasing-deletes-demo/index.js:16:56 + + 12 }, + 13 }) + 14 + 15 try { +→ 16 const deletedUser = await prisma.oneMoreUser.delete(Error occurred during query execution: +ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(SqliteFailure(Error { code: ConstraintViolation, extended_code: 787 }, Some("FOREIGN KEY constraint failed"))) }) + at PrismaClientFetcher.request (/home/justin/prisma/cascading-deletes-demo/node_modules/@prisma/client/index.js:89:17) + at process._tickCallback (internal/process/next_tick.js:68:7) +``` + +### 9.4. Validating `SET NULL` + +The `SET NULL` keyword ensures that when a referenced row is deleted, all the rows that are referencing it reset their foreign key to `NULL`. So, when deleting an `AlmostTheLastUser` record that is referenced by one or more `AlmostTheLastPost` records, these `AlmostTheLastPost` records will reset their `author` fields to `NULL`. + +To test the `SET NULL` behavior, you need to access the `AlmostTheLastUser` and `AlmostTheLastPost` tables. + +Open the `index.js` file and replace its contents with the following code: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.almostTheLastUser.create({ + data: { + name: 'Alice', + almostTheLastPost: { + create: { title: 'Hello World' }, + }, + }, + include: { + almostTheLastPost: true + } + }) + + const postBefore = await prisma.almostTheLastPost.findOne({ + where: { id: userWithPost.almostTheLastPost[0].id }, + include: { author: true } + }) + + console.log(`Before deleting the \`AlmostTheLastUser\` record, the \`AlmostTheLastPost\` record looks as follows:\n${JSON.stringify(postBefore)}`) + + const deletedUser = await prisma.almostTheLastUser.delete({ + where: { id: userWithPost.id }, + }) + + const postAfter = await prisma.almostTheLastPost.findOne({ + where: { id: postBefore.id }, + include: { author: true } + }) + + console.log(`After deleting the \`AlmostTheLastUser\` record, the \`AlmostTheLastPost\` record looks as follows:\n${JSON.stringify(postAfter)}`) +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +The console output will look similar to this: + +``` +$ node index.js +Before deleting the `User` record, the `Post` record looks as follows: +{"id":6,"title":"Hello World","author":{"id":6,"name":"Alice"}} +After deleting the `User` record, the `Post` record looks as follows: +{"id":6,"title":"Hello World","author":null} +``` + +### 9.5. Validating `SET DEFAULT` + +The `SET DEFAULT` keyword ensures that when a referenced row is deleted, all the rows that are referencing it set their foreign key to their default value (if there's no default value defined, it resets the foreign key to `NULL`). So, when deleting an `TheLastUser` record that is referenced by one or more `TheLastPost` records, these `TheLastPost` records will reset their `author` fields to `NULL`. + +To test the `SET DEFAULT` behavior, you need to access the `TheLastUser` and `TheLastPost` tables. + +Open the `index.js` file and replace its contents with the following code: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + const userWithPost = await prisma.theLastUser.create({ + data: { + name: 'Alice', + theLastPost: { + create: { title: 'Hello World' }, + }, + }, + include: { + theLastPost: true + } + }) + + const postBefore = await prisma.theLastPost.findOne({ + where: { id: userWithPost.theLastPost[0].id }, + include: { author: true } + }) + + console.log(`Before deleting the \`TheLastUser\` record, the \`TheLastPost\` record looks as follows:\n${JSON.stringify(postBefore)}`) + + const deletedUser = await prisma.theLastUser.delete({ + where: { id: userWithPost.id }, + }) + + const postAfter = await prisma.theLastPost.findOne({ + where: { id: postBefore.id }, + include: { author: true } + }) + + console.log(`After deleting the \`TheLastUser\` record, the \`TheLastPost\` record looks as follows:\n${JSON.stringify(postAfter)}`) +} + +main() +``` + +Run the code with this command: + +``` +node index.js +``` + +If you run this command and there's no `User` record in the database with an `id` of `42`, the script is going to fail with the following error: + +``` +Before deleting the `TheLastUser` record, the `TheLastPost` record looks as follows: +{"id":4,"title":"Hello World","author":{"id":5,"name":"Alice"}} +(node:43705) UnhandledPromiseRejectionWarning: Error: +Invalid `deletedUser = await prisma.theLastUser.delete()` invocation in +/Users/janedoe/cascasing-deletes-demo/index.js:25:54 + + 21 }) + 22 + 23 console.log([object Object],[object Object],[object Object]) + 24 +→ 25 const deletedUser = await prisma.theLastUser.delete(Error occurred during query execution: +ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(SqliteFailure(Error { code: ConstraintViolation, extended_code: 787 }, Some("FOREIGN KEY constraint failed"))) }) + at PrismaClientFetcher.request (/home/justin/prisma/cascading-deletes-demo/node_modules/@prisma/client/index.js:89:17) + at process._tickCallback (internal/process/next_tick.js:68:7) +(node:3074) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) +(node:3074) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. +``` + +If there is a `User` record with an `id` of `42`, the output will look similar to this: + +``` +$ node index.js +Before deleting the `TheLastUser` record, the `TheLastPost` record looks as follows: +{"id":6,"title":"Hello World","author":{"id":6,"name":"Alice"}} +After deleting the `TheLastUser` record, the `TheLastPost` record looks as follows: +{"id":6,"title":"Hello World","author":{"id":42,"name":"Bob"}} +``` diff --git a/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx b/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx new file mode 100644 index 0000000000..72791482fd --- /dev/null +++ b/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx @@ -0,0 +1,4 @@ +--- +title: "Cascading deletes" +metaTitle: "" +------ diff --git a/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx b/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx new file mode 100644 index 0000000000..171ebfef85 --- /dev/null +++ b/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx @@ -0,0 +1,459 @@ +--- +title: "Data validation with CHECK constraints (PostgreSQL)" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This page explains how to configure [check constraints](https://www.postgresql.org/docs/9.4/ddl-constraints.html#DDL-CONSTRAINTS-CHECK-CONSTRAINTS) in a PostgreSQL database. A check constraint is a condition that must be satisfied before a value can be saved to a table - for example, the discounted price of a product must always be less than the original price. + +Check constraints can be added when you create the table (using `CREATE TABLE`) or to a table that already exists (using `ALTER TABLE`). This guide covers all four combinations. + +At the end of the guide, you'll introspect your database, generate a Prisma Client, and write a simple Node.js script to validate the constraints. + +## Prerequisites + +In order to follow this guide, you need: + +- a [PostgreSQL](https://www.postgresql.org/) database server running +- the [`createdb`](https://www.postgresql.org/docs/9.1/app-createdb.html) command line utility +- the [`psql`]( ) command line client for PostgreSQL +- [Node.js](https://nodejs.org/) installed on your machine + +## 1. Create a new database and project directory + +Start by creating a project directory for the files that you'll create throughout this guide. Open terminal or command line and run the following commands: + +``` +mkdir check-demo +cd check-demo +``` + +Next, make sure that your PostgreSQL database server is running. Authenticate the default `postgres` user: + +Unix (bash): + +``` +sudo -u postgres +``` + +Windows (command line): + +``` +psql -U postgres +``` + +Then execute the following command in your terminal to create a new database called `CheckDemo`: + +Unix (bash): + +``` +createdb CheckDemo +``` + +Windows (command line): + +``` +create database CheckDemo; +\connect CheckDemo +``` + +> *Tip*: Remember the trailing `;`! `postgres=#` `postgres-#` + +You can validate that the database was created by running the `\dt` command which lists all tables (_relations_) in your database (right now there are none): + +Unix (bash): + +``` +psql -d CheckDemo -c "\dt" +``` + +Windows (command line): + +``` +-d CheckDemo -c \dt +``` + +## 2. Adding a table with a single check constraint on a single column + +In this section, you'll **create a new table with a single check constraint on a single column** in the `CheckDemo` database. + +Create a new file called `single-column-check-constraint.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."product" ( + price NUMERIC CONSTRAINT price_value_check CHECK (price > 0.01 AND price <> 1240.00) +); +ALTER TABLE "public"."product" + ADD COLUMN "productid" serial, + ADD PRIMARY KEY ("productid"); +``` + +Now run the SQL statement against your database to create a new table called `product`: + +Unix (bash): + +``` +psql CheckDemo < single-column-check-constraint.sql +``` + +Windows (command line): + +``` +\i 'c:/checkdemo/single-column-check-constraint.sql' +``` + +Congratulations, you just created a table called `product` in the database. The table has one column called `price`, which has a single check constraint that ensures price of a product is: + +* Never less than 0.01 +* Never equal to 1240.00 + +Run the following command to see the a list of check constraints that apply to the `product` table: + +``` +\d+ product +``` + +You will see the following output, which includes a list of all check constraints: + +``` +Table "public.product" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + price | numeric | | | | main | | +Check constraints: + "price_value_check" CHECK (price > 0.01 AND price <> 1240.00) +``` + +Note that PostgreSQL will auto-generate a constraint name if you do not provide one. For example, the constraint created by `price NUMERIC CHECK (price > 0.01 AND price <> 1240.00)` would be `price_check`. + +## 3. Adding a table with a multi-column check constraint + +Next, you'll **create a table with a multi-column check constraint** that compares the values of two columns. + +Create a new file called `multi-column-check-constraint.sql` and add the following code to it: + +```sql +CREATE TABLE "public"."anotherproduct" ( + reducedprice NUMERIC CONSTRAINT reduced_price_check CHECK (price > reducedprice), + price NUMERIC +); +ALTER TABLE "public"."anotherproduct" + ADD COLUMN "productid" serial, + ADD PRIMARY KEY ("productid"); +``` + +Now run the SQL statement against your database to create a new table called `anotherproduct`: + +Unix (bash): + +``` +psql CheckDemo < multi-column-check-constraint.sql +``` + +Windows (command line): + +``` +\i 'c:/checkdemo/multi-column-check-constraint.sql' +``` + +Congratulations, you just created a table called `anotherproduct` in the database. The table has two columns called `reducedprice` and `price`. The `reducedprice` column has a check constraint that ensures that the value of `reducedprice` is always less than the value of `price`. + +## 4. Adding a table with multiple check constraints + +Next, you'll **create a table with multiple check constraint** on different columns. + +Create a new file called `multiple-check-constraints.sql` and add the following code to it: + +```sql + CREATE TABLE "public"."secondtolastproduct" ( + reducedprice NUMERIC CONSTRAINT reduced_price_check CHECK (price > reducedprice), + price NUMERIC, + tags TEXT[] CONSTRAINT tags_contains_product CHECK ('product' = ANY(tags)) + ); +ALTER TABLE "public"."secondtolastproduct" + ADD COLUMN "productid" serial, + ADD PRIMARY KEY ("productid"); +``` + +Now run the SQL statement against your database to create a new table called `secondtolastproduct`: + +Unix (bash): + +``` +psql CheckDemo < multiple-check-constraints.sql +``` + +Windows (command line): + +``` +\i 'c:/checkdemo/multiple-check-constraints.sql' +``` + +Congratulations, you just created a table called `lastproduct` in the database. The table has three colums named `reducedprice`, `price` and `tags`, and the following check constraints: + +* The `tags` column (which is an array) must contain a tag named `product` +* The value of `reducedprice` must be less than the value of `price` + +## 5. Adding a check constraint to an existing table + +In this section, you'll **add a check constraint to a table that already exists in your database**. To do so, you first need to create a new table and then alter the table to add the constraint. + +Create a new file called `add-single-check-constraint-later.sql` and add the following code: + +```sql +CREATE TABLE "public"."lastproduct" ( + category TEXT +); + +ALTER TABLE "public"."lastproduct" + ADD CONSTRAINT "category_not_clothing" CHECK (category <> 'clothing'); +``` + +This code contains two SQL statements: + +1. Create a new table called `lastproduct` +2. Alter the table to add a check constraint named `price_not_zero_constraint` + +Now run the SQL statements against your database to create a new table called `lastproduct`: + +Unix (bash): + +``` +psql CheckDemo < add-single-check-constraint-later.sql +``` + +Windows (command line): + +``` +\i 'c:/checkdemo/add-single-check-constraint-later.sql' +``` + +Congratulations, you just created a table called `lastproduct` in the database with a single column called `price`. You added constraint named `price_not_zero_constraint` to with a second SQL command, which ensures that the price of a product is never less than 0.01. + +### 5. Introspect your database with Prisma + +In the previous sections, you created four tables with different check constraints: + +- The `product` table has a check constraint that ensures that the value of `price` is never less than `0.01` and enver exactly `1240.00`. +- The `anotherproduct` table has a check constraint that ensures that the value of `reducedprice` is never greater than the value of `price`. +- The `secondtolastproduct` table has two check constraints - one that ensures that the value of `reducedprice` is never greater than the value of `price`, and one that ensures that the `tags` array always contains the value `product`. +- The `lastproduct` table has a check constraint that ensures that the value of `category` is never `clothing`. + +In this section you'll introspect your database to generate the Prisma models for these tables. + +> **Note**: Check constraints are currently not included in the generated Prisma schema - however, the underlying database still enforces the constraints. + +To start, set up a new Node.js project and add the `prisma2` CLI as a development dependency: + +``` +npm init -y +npm install prisma2 --save-dev +``` + +In order to introspect your database, you need to tell Prisma how to connect to it. You do so by configuring a `datasource` in your Prisma schema. + +Create a new file called `schema.prisma` and add the following code to it: + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} +``` + +The database connection URL is set via an environment variable. The Prisma CLI automatically supports the [`dotenv`]() format which automatically picks up environment variables defined in a file called `.env`. + +Create a new file called `.env` and set your database connection URL as the `DATABASE_URL` environment variable: + +``` +DATABASE_URL=postgresql://__USER__:__PASSWORD__@__HOST__:__PORT__/CheckDemo +``` + +In the above code snippet, you need to replace the uppercase placeholders with your own connection details. For example, if your database is running locally it could look like this: + +``` +DATABASE_URL=postgresql://janedoe:mypassword@localhost:5432/CheckDemo +``` + +With both the `schema.prisma` and `.env` files in place, you can run Prisma's introspection with the following command: + +``` +npx prisma introspect +``` + +This command introspects your database and for each table adds a Prisma model to the Prisma schema: + +```prisma +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model anotherproduct { + price Float? + productid Int @id + reducedprice Float? +} + +model lastproduct { + category String? + productid Int @id +} + +model product { + price Float? + productid Int @id +} + +model secondtolastproduct { + price Float? + productid Int @id + reducedprice Float? + tags String[] +} +``` + +## 7. Generate Prisma Client + +To validate whether the check constraints work, you'll now generate Prisma Client and send a few sample queries to the database. + +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): + +```prisma + generator client { + provider = "prisma-client-js" + } +``` + +Run the following command to install and generate Prisma Client in your project: + +``` +npx prisma2 generate +``` + +Now you can use Prisma Client to send database queries in Node.js. + +## 8. Validate the check constraints in a Node.js script + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + + const newProduct = await prisma.product.create({ + data: { + price: 0.00 + } + }); + + console.log(newProduct); + +} + +main() +``` + +In this code, you're creating a product with a price of `0.00`, which does not meet the check constraint configured for the `price` column. + +Run the code with this command: + +``` +node index.js +``` + +The script throws an error indicating that the `price_check_value` check constraint was not met: + +``` +Error occurred during query execution: +ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: Db, cause: Some(DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState("23514"), message: "new row for relation \"product\" violates check constraint \"price_value_check\"", detail: Some("Failing row contains (0, 11)."), hint: None, position: None, where_: None, schema: Some("public"), table: Some("product"), column: None, datatype: None, constraint: Some("price_value_check"), file: Some("d:\\pginstaller_12.auto\\postgres.windows-x64\\src\\backend\\executor\\execmain.c"), line: Some(2023), routine: Some("ExecConstraints") }) }) }) +``` + +To validate the multi-column check constraint, replace the code in `index.js` with the following: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + + const newProduct = await prisma.anotherproduct.create({ + data: { + price: 50.00, + reducedprice: 100.00 + } + }); + + console.log(newProduct); + +} + +main() +``` + +In this code, you're creating a product where the reduced price is higher than the actual price. + +Run the script again with this command: + +``` +node index.js +``` + +This time, you'll see a similar error message indicating the `reduce_price_check` check constraint was not met: + +``` +ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: Db, cause: Some(DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState("23514"), message: "new row for relation \"anotherproduct\" violates check constraint \"reduced_price_check\"", detail: Some("Failing row contains (100, 50, 1)."), hint: None, position: None, where_: None, schema: Some("public"), table: Some("anotherproduct"), column: None, datatype: None, constraint: Some("reduced_price_check"), file: Some("d:\\pginstaller_12.auto\\postgres.windows-x64\\src\\backend\\executor\\execmain.c"), line: Some(2023), routine: Some("ExecConstraints") }) }) }) + at PrismaClientFetcher.request (C:\Work\Personal\prisma-check-constraint\node_modules\@prisma\client\index.js:89:17) +``` + +Finally, modify the script to include multiple check constraint violations: + +```js +const { PrismaClient } = require('@prisma/client') + +const prisma = new PrismaClient() + +async function main() { + + const newProduct = await prisma.secondtolastproduct.create({ + data: { + tags: { + set: [ "wrongtag" ] + }, + price: 90.00, + reducedprice: 100.00 + } + }); + + console.log(newProduct); + +} + +main() +``` + +In this code, you're creating a product where the reduced price is higher than the actual price, and omitting the required `product` tag. + +Run the script again with this command: + +``` +node index.js +``` + +Notice that the error message only mentions the `reduced_price_check` constraint: + +``` +ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: Db, cause: Some(DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState("23514"), message: "new row for relation \"secondtolastproduct\" violates check constraint \"reduced_price_check\"", detail: Some("Failing row contains (100, 90, {wrongtag}, 7)."), hint: None, position: None, where_: None, schema: Some("public"), table: Some("secondtolastproduct"), column: None, datatype: None, constraint: Some("reduced_price_check"), file: Some("d:\\pginstaller_12.auto\\postgres.windows-x64\\src\\backend\\executor\\execmain.c"), line: Some(2023), routine: Some("ExecConstraints") }) }) }) +``` + +Check constraints are resolved in alphabetical order, and only the first constraint to fail appears in the error message. \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx b/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx new file mode 100644 index 0000000000..f336097fb9 --- /dev/null +++ b/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx @@ -0,0 +1,10 @@ +--- +title: "Data validation with CHECK constraints (MySQL)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 + + + diff --git a/content/04-guides/01-database-workflows/07-data-validation/03-sqlite.mdx b/content/04-guides/01-database-workflows/07-data-validation/03-sqlite.mdx new file mode 100644 index 0000000000..e2cc0be6dd --- /dev/null +++ b/content/04-guides/01-database-workflows/07-data-validation/03-sqlite.mdx @@ -0,0 +1,7 @@ +--- +title: "Data validation with CHECK constraints (SQLite)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 diff --git a/content/04-guides/01-database-workflows/07-data-validation/index.mdx b/content/04-guides/01-database-workflows/07-data-validation/index.mdx new file mode 100644 index 0000000000..94cc322b4d --- /dev/null +++ b/content/04-guides/01-database-workflows/07-data-validation/index.mdx @@ -0,0 +1,4 @@ +--- +title: "Data validation" +metaTitle: "" +--- \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/index.mdx b/content/04-guides/01-database-workflows/index.mdx new file mode 100644 index 0000000000..749172b6c6 --- /dev/null +++ b/content/04-guides/01-database-workflows/index.mdx @@ -0,0 +1,5 @@ +--- + title: "Database workflows" + metaTitle: "Guides" + staticLink: true +--- \ No newline at end of file diff --git a/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx b/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx new file mode 100644 index 0000000000..49a874d306 --- /dev/null +++ b/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx @@ -0,0 +1,210 @@ +--- +title: "Deploying to ZEIT Now" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +In this guide, you will set up and deploy a serverless Node.js application to [ZEIT Now](https://zeit.co/home). The application will expose a REST API and use Prisma Client to handle fetching, creating, and deleting records from a database. + +ZEIT Now is a cloud platform for static sites and serverless functions. Typically Now integrates with a Git repository for automatic deployments upon commits. For the sake of simplicity, this guide uses the Now CLI which allows deploying directly from the command line. + +The application has the following components: + +- **Backend**: Serverless Node.js REST API with resource endpoints that use Prisma Client to handle database operations against a PostgreSQL database (e.g. hosted on Heroku). +- **Frontend**: Static HTML page to interact with the API. + +![architecture diagram](https://imgur.com/L45Ye7ze.png) + +The focus of this guide is showing how Prisma integrates with ZEIT Now. The starting point will the [Prisma ZEIT Now example](https://github.com/prisma/prisma-examples/tree/prisma2/deployment-platforms/zeit-now) which has a couple of REST endpoints preconfigured as serverless functions and a static page. + +> Throughout the guide you'll find various **checkpoints** that enable you to validate whether you performed the steps correctly. + +## Prerequisites + +- Hosted PostgreSQL database and a URL from which it can be accessed, e.g. `postgresql://username:password@your_postgres_db.cloud.com/db_identifier` (you can use Heroku, which offers a free plan). +- [ZEIT Now](https://zeit.co) account. +- [Now CLI](https://zeit.co/download) installed. +- Node.js installed. +- PostgreSQL CLI `psql` installed. + +## Prisma workflow + +Prisma supports different workflows depending on whether you integrate with an existing database or create a new one from scratch. Regardless of the workflow, Prisma relies on the Prisma schema, i.e. `schema.prisma` file. + +This guide starts with an empty database created with plain SQL and looks as follows: + +1. Define the database schema using SQL. +1. Run `prisma2 introspect` which will introspect and populate the `prisma.schema` with models based on the database schema +1. Run `prisma2 generate` which will generate Prisma Client based on the Prisma schema. + +## 1. Download the example + + + +Open your terminal and navigate to a location of your choice. Create the directory that will hold the application code and download the example code: + +```sh +mkdir prisma-zeit-now +cd prisma-zeit-now +curl https://codeload.github.com/prisma/prisma-examples/tar.gz/prisma2-deployment-zeit | tar -xz --strip=3 prisma-examples-prisma2-deployment-zeit/deployment-platforms/zeit-now/ # change link from 2color fork to Prisma once example is merged + # tar strip folder is a concatenation of the REPOSITORY-BRANCH/REF, e.g. prisma-examples-prisma2 +``` + + + +**Checkpoint:** `ls -1` should show: + +```sh +ls -1 +README.md +api +now.json +package.json +public +``` + +## 2. ZEIT Now login + +Make sure you're logged in to ZEIT Now with the CLI: + +```sh +now login +``` + +This will allow you to deploy to ZEIT Now from the terminal. + +**Checkpoint:** `now whoami` should show your username: + +```sh +now whoami +Now CLI 17.0.3 +> your-username +``` + +## 3. Create the database schema + +To create your database schema, run the `schema.sql` from the example code as follows: + +```sh +psql postgresql://__USER__:__PASSWORD__@__HOST__/__DATABASE__ -f schema.sql +``` + +Note that the long starting with `postgresql://` will be referred to as the `DATABASE_URL` which you'll also need for the subsequent steps. You need to replace the uppercase placeholders with your database credentials, e.g.: + +```sh +psql postgresql://janedoe:randompassword@yourpostgres.compute-1.amazonaws.com:5432/yourdbname -f schema.sql +``` + +**Checkpoint:** `psql $DATABASE_URL -c "\dt"` should show the list of tables: + + List of relations + Schema | Name | Type | Owner + --------+---------+-------+---------------- + public | Post | table | janedoe + public | Profile | table | janedoe + public | User | table | janedoe + +Congratulations, you have successfully created the database schema. + +## 4. Set the DATABASE_URL env var + +Set the `DATABASE_URL` environment variable locally so that Prisma can access the database to introspect: + +```sh +export DATABASE_URL="postgresql://__USER__:__PASSWORD__@__HOST__/__DATABASE__" +``` + +It's considered best practice to keep secrets out of your codebase. If you open up the `prisma/schema.prisma` file, you should see `env("DATABASE_URL")` in the _datasource_ block. By setting an environment variable you keep secrets out of the codebase. + +## 5. Introspect the database + +Introspect the database with the Prisma CLI: + +```sh +npx prisma2 introspect +``` + +Prisma will introspect the database defined in the `datasource` block of the Prisma schema and populate the Prisma schema with models corresponding to the database tables. + +**Checkpoint:** Open `schema.prisma` and ensure there are three models: `Post`, `Profile`, and `User`. + +## 6. Define Now secret and expose to functions + +In step 4 you set the `DATABASE_URL` environment variable on your machine. For the application to work, `DATABASE_URL` also needs to be available to Now's serverless functions. + +Adding environment variables to Now requires two steps: + +1. Defining a [Now secret](https://zeit.co/docs/v2/build-step#using-environment-variables-and-secrets) via the Now CLI with `now secrets add`. +2. Exposing the secret to your serverless functions in your `now.json` file. + +```sh +now secrets add database_url "$DATABASE_URL" +``` + +This uses the `$DATABASE_URL` environment variable defined in step 4. + +Using the `now.json` configuration file, you can set Now related configuration, such as routing and environment variables. The `now.json` from the example will contain the configuration for making the secret available as an environment variable: + +```json +// now.json +{ + // ... + "env": { + "DATABASE_URL": "@database_url" + }, + "build": { + "env": { + "DATABASE_URL": "@database_url" + } + } +} +``` + +The configuration exposes the Now secret `database_url` as an environment variable named `DATABASE_URL` to both the build and run time. Prisma will use `DATABASE_URL` to connect to your database whenever the functions run. + +## 7. Deploy to now + +Deploy the app from the project's root: + +```sh +now +``` + +After prompting you to pick a Now project name, it will deploy the app and log the preview URL. + +**Checkpoint:** Make a request to the preview URL's API root: + +```sh +curl https://PROJECT_NAME.NOW_USERNAME.now.sh/api +``` + +The call should return: `{"up":true}` + +## 8. Test your deployed application + +You can use the static frontend to interact with the API you deployed via the preview URL. + +Open up the preview URL in your browser, the URL should like this: `https://PROJECT_NAME.NOW_USERNAME.now.sh`. You should see the following: + +![deployed-screenshot](https://imgur.com/y7yGDAb.pngs) + +The four buttons allow you to make requests to the REST API and view the response: + +- **Check API status**: Will call the REST API status endpoint that returns `{"up":true}`. The implementation code is in `api/index.js` +- **Seed data**: Will delete all database records and load the database with test data `users`, `profiles`, and `posts`. Returns the created users. The implementation code is in `api/seed.js` +- **Load users with profiles**: Will load all `users` in the database with their related `profiles`. The implementation code is in `api/getUsers.js` +- **Load Posts**: Will load `posts` and their related `authors`. The implementation code is in `api/getPosts.js` + +For example, calling seed data should show the following: + +![deployed-seed-endpoint-screenshot](https://imgur.com/mThW4Na.png) + +## Summary + +Congratulations! You have successfully deployed the application to Now. + +For more insight into Prisma Client's API, look at the function handlers in the `api/` folder. + +Generally, when using a FaaS (function as a service) environment to interact with a database, it's beneficial to pool DB connections for performance reasons. This is because every function invocation may result in a new connection to the database (this is not a problem with a constantly running node.js server). For more information on some of the solutions, you may want to look at our [general FaaS guide](https://github.com/prisma/prisma2/blob/master/docs/prisma-client-js/deployment.md#database-connection-handling). diff --git a/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx b/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx new file mode 100644 index 0000000000..ec7afee84b --- /dev/null +++ b/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx @@ -0,0 +1,8 @@ +--- +title: "Deploying to AWS Lambda" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 + diff --git a/content/04-guides/02-deployment/03-deploying-to-heroku.mdx b/content/04-guides/02-deployment/03-deploying-to-heroku.mdx new file mode 100644 index 0000000000..fe82553ea2 --- /dev/null +++ b/content/04-guides/02-deployment/03-deploying-to-heroku.mdx @@ -0,0 +1,8 @@ +--- +title: "Deploying to Heroku" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 + From 96a39c147e8dcbc806432934ba32b7f2f636e07d Mon Sep 17 00:00:00 2001 From: Nilu Date: Fri, 20 Mar 2020 18:33:32 +0100 Subject: [PATCH 08/33] Add content --- content/04-guides/02-deployment/index.mdx | 6 ++++++ gatsby-node.js | 10 ++++++++++ src/layouts/articleLayout.tsx | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 content/04-guides/02-deployment/index.mdx diff --git a/content/04-guides/02-deployment/index.mdx b/content/04-guides/02-deployment/index.mdx new file mode 100644 index 0000000000..6cbd508dab --- /dev/null +++ b/content/04-guides/02-deployment/index.mdx @@ -0,0 +1,6 @@ +--- + title: "Deployment" + metaTitle: "" + metaDescription: "" + staticLink: true +--- \ No newline at end of file diff --git a/gatsby-node.js b/gatsby-node.js index 3cce54875d..2d0d704676 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -27,6 +27,16 @@ exports.onCreateNode = ({ node, getNode, actions }) => { node, value: node.frontmatter.title || parent.name, }); + createNodeField({ + name: 'metaTitle', + node, + value: node.frontmatter.metaTitle || '', + }); + createNodeField({ + name: 'metaDescription', + node, + value: node.frontmatter.metaDescription || '', + }); createNodeField({ name: 'staticLink', node, diff --git a/src/layouts/articleLayout.tsx b/src/layouts/articleLayout.tsx index c4efeece5e..4ee4f68217 100644 --- a/src/layouts/articleLayout.tsx +++ b/src/layouts/articleLayout.tsx @@ -59,7 +59,7 @@ const ArticleLayout = ({ data, ...props }: ArticleLayoutProps) => { return ( - + Date: Fri, 20 Mar 2020 19:03:56 +0100 Subject: [PATCH 09/33] fix frontmatter --- .../02-importing-and-exporting-data/index.mdx | 2 +- .../04-guides/01-database-workflows/05-foreign-keys/index.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx index 7547dd1f02..747420cef0 100644 --- a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx @@ -1,4 +1,4 @@ --- title: "Importing and exporting data"" metaTitle: "" ------- \ No newline at end of file +--- \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx index d114bbc945..9ae5a17f8b 100644 --- a/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx +++ b/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx @@ -1,4 +1,4 @@ --- title: "Foreign keys" metaTitle: "" ------- \ No newline at end of file +--- \ No newline at end of file From eae7b8b83a54b918d08cdd7072043ef0d786039d Mon Sep 17 00:00:00 2001 From: Nilu Date: Fri, 20 Mar 2020 19:30:51 +0100 Subject: [PATCH 10/33] Prettified files --- .prettierrc | 8 +- content/01-getting-started/02-quickstart.mdx | 10 +- .../01-add-to-an-existing-project.mdx | 11 +- .../02-start-from-scratch-sql-migrations.mdx | 540 +++++++++--------- .../03-start-from-scratch-prisma-migrate.mdx | 169 +++--- .../03-setup-prisma/index.mdx | 10 +- content/01-getting-started/index.mdx | 8 +- .../02-understand-prisma/01-introduction.mdx | 8 +- content/02-understand-prisma/02-features.mdx | 23 +- .../index.mdx | 7 +- .../04-is-prisma-an-orm.mdx | 41 +- .../02-understand-prisma/05-data-modeling.mdx | 41 +- content/02-understand-prisma/index.mdx | 7 +- .../01-what-is-the-prisma-schema.mdx | 16 +- .../01-schema/02-data-sources.mdx | 6 +- .../01-schema/03-generators.mdx | 2 +- .../01-schema/05-models.mdx | 24 +- .../01-schema/06-relations.mdx | 9 +- .../01-schema/index.mdx | 10 +- .../01-generating-prisma-client.mdx | 43 +- .../02-configuring-the-prisma-client-api.mdx | 52 +- .../02-prisma-client/05-field-selection.mdx | 179 +++--- .../06-raw-database-access.mdx | 20 +- .../07-connection-management.mdx | 14 +- .../02-prisma-client/08-generated-types.mdx | 46 +- .../02-prisma-client/09-filtering.mdx | 2 +- .../02-prisma-client/10-ordering.mdx | 2 +- .../02-prisma-client/11-pagination.mdx | 2 +- .../02-prisma-client/14-error-formatting.mdx | 10 +- .../02-prisma-client/15-transactions.mdx | 49 +- .../02-prisma-client/17-query-engine.mdx | 11 +- .../02-prisma-client/19-api.mdx | 6 +- .../02-prisma-client/index.mdx | 7 +- .../03-prisma-migrate/index.mdx | 9 +- .../04-introspection.mdx | 8 +- .../05-prisma-cli/01-installation.mdx | 5 +- .../05-prisma-cli/02-command-reference.mdx | 119 ++-- .../05-prisma-cli/index.mdx | 8 +- .../01-tools-and-interfaces/index.mdx | 10 +- .../02-database-connectors/01-postgresql.mdx | 2 +- .../02-database-connectors/02-mysql.mdx | 2 +- .../02-database-connectors/03-sqlite.mdx | 2 +- .../02-database-connectors/index.mdx | 10 +- .../03-reference/03-more/01-editor-setup.mdx | 2 +- content/03-reference/03-more/02-telemetry.mdx | 2 +- content/03-reference/03-more/index.mdx | 10 +- content/03-reference/index.mdx | 8 +- .../01-postgresql.mdx | 1 - .../01-setting-up-a-database/02-mysql.mdx | 3 - .../01-setting-up-a-database/index.mdx | 2 +- .../01-postgresql.mdx | 41 +- .../02-mysql.mdx | 36 +- .../02-importing-and-exporting-data/index.mdx | 4 +- .../03-primary-keys/01-postgresql.mdx | 1 - .../03-primary-keys/02-mysql.mdx | 3 - .../03-primary-keys/index.mdx | 2 +- .../index.mdx | 2 +- .../05-foreign-keys/02-mysql.mdx | 36 +- .../05-foreign-keys/index.mdx | 2 +- .../06-cascading-deletes/index.mdx | 2 +- .../07-data-validation/01-postgresql.mdx | 74 ++- .../07-data-validation/02-mysql.mdx | 3 - .../07-data-validation/index.mdx | 2 +- .../04-guides/01-database-workflows/index.mdx | 8 +- .../02-deploying-to-aws-lambda.mdx | 1 - .../02-deployment/03-deploying-to-heroku.mdx | 1 - content/04-guides/02-deployment/index.mdx | 10 +- content/04-guides/index.mdx | 8 +- package.json | 2 +- src/components/customMdx/code.tsx | 6 +- src/components/customMdx/copy.tsx | 39 +- src/components/customMdx/index.tsx | 42 +- src/components/customMdx/pre.tsx | 18 +- src/components/footer.tsx | 43 +- src/components/header.tsx | 43 +- src/components/image.tsx | 6 +- src/components/layout.css | 26 +- src/components/layout.tsx | 29 +- src/components/pageBottom.tsx | 12 +- src/components/seo.tsx | 4 +- src/components/sidebar/index.tsx | 10 +- src/components/sidebar/tree.tsx | 35 +- src/components/sidebar/treeNode.tsx | 36 +- src/components/toc.tsx | 38 +- src/components/topSection.tsx | 8 +- src/hooks/useAllArticlesQuery.ts | 4 +- src/hooks/useLayoutQuery.ts | 4 +- src/hooks/useTOCQuery.ts | 4 +- src/icons/ArrowDown.tsx | 2 +- src/icons/ArrowEmail.tsx | 2 +- src/icons/ArrowRight.tsx | 2 +- src/icons/Copy.tsx | 2 +- src/icons/Down.tsx | 10 +- src/icons/Email.tsx | 2 +- src/icons/Facebook.tsx | 10 +- src/icons/Git.tsx | 2 +- src/icons/GitGrey.tsx | 10 +- src/icons/Logo.tsx | 2 +- src/icons/PrismaLogoGrey.tsx | 10 +- src/icons/Search.tsx | 2 +- src/icons/Slack.tsx | 10 +- src/icons/Twitter.tsx | 10 +- src/icons/Up.tsx | 10 +- src/icons/Youtube.tsx | 10 +- src/interfaces/AllArticles.interface.ts | 4 +- src/interfaces/Article.interface.ts | 2 +- src/interfaces/Layout.interface.ts | 1 - src/interfaces/TOC.interface.ts | 2 +- src/layouts/articleLayout.tsx | 45 +- src/pages/404.tsx | 4 +- src/pages/index.tsx | 25 +- src/utils/stringify.ts | 80 +-- 112 files changed, 1188 insertions(+), 1312 deletions(-) diff --git a/.prettierrc b/.prettierrc index cfb30e46bd..40986f84b9 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,7 @@ { - "semi": true, - "singleQuote": true, + "printWidth": 100, + "jsxBracketSameLine": false, + "singleQuote": false, + "tabWidth": 2, "trailingComma": "es5" -} \ No newline at end of file +} diff --git a/content/01-getting-started/02-quickstart.mdx b/content/01-getting-started/02-quickstart.mdx index 43abf74903..7da792f10d 100644 --- a/content/01-getting-started/02-quickstart.mdx +++ b/content/01-getting-started/02-quickstart.mdx @@ -1,8 +1,8 @@ --- - title: "Quickstart" - metaTitle: "" - metaDescription: "" - duration: "5 min" +title: "Quickstart" +metaTitle: "" +metaDescription: "" +duration: "5 min" --- -Coming 🔜 \ No newline at end of file +Coming 🔜 diff --git a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx index c6a7070837..32e158faca 100644 --- a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx +++ b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx @@ -1,14 +1,14 @@ --- - title: "Add Prisma to an existing project" - metaTitle: "" - metaDescription: "" +title: "Add Prisma to an existing project" +metaTitle: "" +metaDescription: "" --- ## Overview **Note: The content of this page is temporary and will be updated soon.** -This page explains how to get started with Prisma in an existing project. +This page explains how to get started with Prisma in an existing project. If you don't have a database to try Prisma or just want to explore everything from scratch, check out the ready-to-run [example projects](https://github.com/prisma/prisma-examples/) with use cases for REST, GraphQL, gRPC and more. @@ -26,5 +26,4 @@ Follow these steps to use Prisma in an existing application with a database. Not 1. Instantiate Prisma Client: `const prisma = new PrismaClient()` 1. Use Prisma Client in code (use your editor's auto-completion to explore its API) -> **Note**: If Prisma's introspection failed for your database schema, please [open an issue](https://github.com/prisma/prisma2/issues/new) and tell us what went wrong. If you want to help us make Prisma more resilient, please [share your database SQL schema with us](https://github.com/prisma/prisma2/issues/757) so we can add it to our introspection testing suite. - +> **Note**: If Prisma's introspection failed for your database schema, please [open an issue](https://github.com/prisma/prisma2/issues/new) and tell us what went wrong. If you want to help us make Prisma more resilient, please [share your database SQL schema with us](https://github.com/prisma/prisma2/issues/757) so we can add it to our introspection testing suite. diff --git a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx index 436f31b403..e483d34d82 100644 --- a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx +++ b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx @@ -1,7 +1,7 @@ --- - title: "Start from scratch (SQL migrations)" - metaTitle: "" - metaDescription: "" +title: "Start from scratch (SQL migrations)" +metaTitle: "" +metaDescription: "" --- **Note: The content of this page is temporary and will be updated soon.** @@ -14,101 +14,105 @@ Follow these steps for an initial Prisma setup: 1. Run `cd hello-prisma` to navigate into it 1. Run `touch schema.prisma` to create an empty [Prisma schema](../../prisma-schema-file.md) 1. Add a `datasource` to the Prisma schema and set your database connection string as the `url`, e.g.: - ```prisma - datasource db { - provider = "postgresql" - url = "postgresql://janedoe:janedoe@localhost:5432/hello-prisma" - } - ``` + ```prisma + datasource db { + provider = "postgresql" + url = "postgresql://janedoe:janedoe@localhost:5432/hello-prisma" + } + ``` 1. Run `touch schema.sql` to create your SQL schema and add the following contents to it: - ```sql - CREATE TABLE "public"."User" ( - user_id SERIAL PRIMARY KEY NOT NULL, - name VARCHAR(255), - email VARCHAR(255) UNIQUE NOT NULL - ); - - CREATE TABLE "public"."Post" ( - post_id SERIAL PRIMARY KEY NOT NULL, - title VARCHAR(255) NOT NULL, - content TEXT, - author_id INTEGER, - FOREIGN KEY (author_id) REFERENCES "public"."User"(user_id) - ); - - CREATE TABLE "public"."Profile" ( - profile_id SERIAL PRIMARY KEY NOT NULL, - bio TEXT, - user_id INTEGER NOT NULL, - FOREIGN KEY (user_id) REFERENCES "public"."User"(user_id) - ); - ``` + + ```sql + CREATE TABLE "public"."User" ( + user_id SERIAL PRIMARY KEY NOT NULL, + name VARCHAR(255), + email VARCHAR(255) UNIQUE NOT NULL + ); + + CREATE TABLE "public"."Post" ( + post_id SERIAL PRIMARY KEY NOT NULL, + title VARCHAR(255) NOT NULL, + content TEXT, + author_id INTEGER, + FOREIGN KEY (author_id) REFERENCES "public"."User"(user_id) + ); + + CREATE TABLE "public"."Profile" ( + profile_id SERIAL PRIMARY KEY NOT NULL, + bio TEXT, + user_id INTEGER NOT NULL, + FOREIGN KEY (user_id) REFERENCES "public"."User"(user_id) + ); + ``` + 1. Run the following command to migrate your database schema: - ``` - psql -h __HOST__ -d __DATABASE__ -U __USER__ -f schema.sql - ``` - Note that you need to replace the uppercase placeholders with your database credentials, e.g.: - ``` - psql -h localhost -d hello-prisma -U janedoe -f schema.sql - ``` + ``` + psql -h __HOST__ -d __DATABASE__ -U __USER__ -f schema.sql + ``` + Note that you need to replace the uppercase placeholders with your database credentials, e.g.: + ``` + psql -h localhost -d hello-prisma -U janedoe -f schema.sql + ``` 1. Add a `generator` to the Prisma schema to be able to generate Prisma Client: - ```prisma - generator client { - provider = "prisma-client-js" - } - ``` + ```prisma + generator client { + provider = "prisma-client-js" + } + ``` 1. Configure project (TypeScript): - ``` - npm init -y - npm install typescript ts-node prisma2 --save-dev - npm install @prisma/client - ``` + ``` + npm init -y + npm install typescript ts-node prisma2 --save-dev + npm install @prisma/client + ``` 1. Run `npx prisma2 introspect` to introspect your database and add your models to the Prisma schema 1. Run `npx prisma2 generate` to generate Prisma Client 1. Run `touch tsconfig.json` and the following contents to it: - ```json - { - "compilerOptions": { - "sourceMap": true, - "outDir": "dist", - "strict": true, - "lib": ["esnext", "dom"], - "esModuleInterop": true - } - } - ``` + ```json + { + "compilerOptions": { + "sourceMap": true, + "outDir": "dist", + "strict": true, + "lib": ["esnext", "dom"], + "esModuleInterop": true + } + } + ``` 1. Run `touch index.ts` to create a source file and add the following code: - ```ts - import { PrismaClient } from '@prisma/client' - - const prisma = new PrismaClient() - - // A `main` function so that we can use async/await - async function main() { - const user1 = await prisma.user.create({ - data: { - email: 'alice@prisma.io', - name: 'Alice', - post: { - create: { - title: 'Watch the talks from Prisma Day 2019', - content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', - }, - }, - }, - include: { - post: true, - }, - }) - console.log(user1) - } - - main() - .catch(e => console.error(e)) - .finally(async () => { - await prisma.disconnect() - }) - ``` + + ```ts + import { PrismaClient } from "@prisma/client"; + + const prisma = new PrismaClient(); + + // A `main` function so that we can use async/await + async function main() { + const user1 = await prisma.user.create({ + data: { + email: "alice@prisma.io", + name: "Alice", + post: { + create: { + title: "Watch the talks from Prisma Day 2019", + content: "https://www.prisma.io/blog/z11sg6ipb3i1/", + }, + }, + }, + include: { + post: true, + }, + }); + console.log(user1); + } + + main() + .catch(e => console.error(e)) + .finally(async () => { + await prisma.disconnect(); + }); + ``` + 1. Run `npx ts-node index.ts` to execute the script ## MySQL @@ -119,106 +123,109 @@ Follow these steps for an initial Prisma setup: 1. Run `cd hello-prisma` to navigate into it 1. Run `touch schema.prisma` to create an empty [Prisma schema](../../prisma-schema-file.md) 1. Add a `datasource` to the Prisma schema and set your database connection string as the `url`, e.g.: - ```prisma - datasource db { - provider = "mysql" - url = "mysql://root:admin@localhost:3306/hello-prisma" - } - ``` + ```prisma + datasource db { + provider = "mysql" + url = "mysql://root:admin@localhost:3306/hello-prisma" + } + ``` 1. Run `touch schema.sql` to create your SQL schema and add the following contents to it: - ```sql - CREATE TABLE User ( - user_id BIGINT NOT NULL AUTO_INCREMENT, - name VARCHAR(255), - email VARCHAR(255) UNIQUE NOT NULL, - PRIMARY KEY (user_id) - ); - - CREATE TABLE Post ( - post_id BIGINT NOT NULL AUTO_INCREMENT, - title VARCHAR(255) NOT NULL, - content TEXT, - author_id BIGINT, - PRIMARY KEY (post_id), - FOREIGN KEY (author_id) REFERENCES User(user_id) - ); - - CREATE TABLE Profile ( - profile_id BIGINT NOT NULL AUTO_INCREMENT, - bio TEXT, - user_id BIGINT NOT NULL, - PRIMARY KEY (profile_id), - FOREIGN KEY (user_id) REFERENCES User(user_id) - ); - ``` + + ```sql + CREATE TABLE User ( + user_id BIGINT NOT NULL AUTO_INCREMENT, + name VARCHAR(255), + email VARCHAR(255) UNIQUE NOT NULL, + PRIMARY KEY (user_id) + ); + + CREATE TABLE Post ( + post_id BIGINT NOT NULL AUTO_INCREMENT, + title VARCHAR(255) NOT NULL, + content TEXT, + author_id BIGINT, + PRIMARY KEY (post_id), + FOREIGN KEY (author_id) REFERENCES User(user_id) + ); + + CREATE TABLE Profile ( + profile_id BIGINT NOT NULL AUTO_INCREMENT, + bio TEXT, + user_id BIGINT NOT NULL, + PRIMARY KEY (profile_id), + FOREIGN KEY (user_id) REFERENCES User(user_id) + ); + ``` + 1. Run the following command to migrate your database schema: - ``` - mysql -u __USER__ -p __DATABASE__ < schema.sql - ``` - Note that you need to replace the uppercase placeholders with your database credentials, e.g.: - ``` - mysql -u root -p hello-prisma < schema.sql - ``` + ``` + mysql -u __USER__ -p __DATABASE__ < schema.sql + ``` + Note that you need to replace the uppercase placeholders with your database credentials, e.g.: + ``` + mysql -u root -p hello-prisma < schema.sql + ``` 1. Add a `generator` to the Prisma schema to be able to generate Prisma Client: - ```prisma - generator client { - provider = "prisma-client-js" - } - ``` + ```prisma + generator client { + provider = "prisma-client-js" + } + ``` 1. Configure project (TypeScript): - ``` - npm init -y - npm install typescript ts-node prisma2 --save-dev - npm install @prisma/client - ``` + ``` + npm init -y + npm install typescript ts-node prisma2 --save-dev + npm install @prisma/client + ``` 1. Run `npx prisma2 introspect` to introspect your database and add your models to the Prisma schema 1. Run `npx prisma2 generate` to generate Prisma Client 1. Run `touch tsconfig.json` and the following contents to it: - ```json - { - "compilerOptions": { - "sourceMap": true, - "outDir": "dist", - "strict": true, - "lib": ["esnext", "dom"], - "esModuleInterop": true - } - } - ``` + ```json + { + "compilerOptions": { + "sourceMap": true, + "outDir": "dist", + "strict": true, + "lib": ["esnext", "dom"], + "esModuleInterop": true + } + } + ``` 1. Run `touch index.ts` to create a source file and add the following code: - ```ts - import { PrismaClient } from '@prisma/client' - - const prisma = new PrismaClient() - - // A `main` function so that we can use async/await - async function main() { - const user1 = await prisma.user.create({ - data: { - email: 'alice@prisma.io', - name: 'Alice', - post: { - create: { - title: 'Watch the talks from Prisma Day 2019', - content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', - }, - }, - }, - include: { - post: true, - }, - }) - console.log(user1) - } - - main() - .catch(e => console.error(e)) - .finally(async () => { - await prisma.disconnect() - }) - ``` -1. Run `npx ts-node index.ts` to execute the script + ```ts + import { PrismaClient } from "@prisma/client"; + + const prisma = new PrismaClient(); + + // A `main` function so that we can use async/await + async function main() { + const user1 = await prisma.user.create({ + data: { + email: "alice@prisma.io", + name: "Alice", + post: { + create: { + title: "Watch the talks from Prisma Day 2019", + content: "https://www.prisma.io/blog/z11sg6ipb3i1/", + }, + }, + }, + include: { + post: true, + }, + }); + console.log(user1); + } + + main() + .catch(e => console.error(e)) + .finally(async () => { + await prisma.disconnect(); + }); + ``` + +1. Run `npx ts-node index.ts` to execute the script ## SQLite @@ -228,96 +235,99 @@ Follow these steps for an initial Prisma setup: 1. Run `cd hello-prisma` to navigate into it 1. Run `touch schema.prisma` to create an empty [Prisma schema](../../prisma-schema-file.md) 1. Add a `datasource` to the Prisma schema and set your database connection string as the `url`, e.g.: - ```prisma - datasource db { - provider = "sqlite" - url = "file:./hello-prisma.db" - } - ``` + ```prisma + datasource db { + provider = "sqlite" + url = "file:./hello-prisma.db" + } + ``` 1. Run `touch schema.sql` to create your SQL schema and add the following contents to it: - ```sql - CREATE TABLE User ( - user_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - name VARCHAR(255), - email VARCHAR(255) UNIQUE NOT NULL - ); - - CREATE TABLE Post ( - post_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - title VARCHAR(255) NOT NULL, - content TEXT, - author_id INTEGER, - FOREIGN KEY (author_id) REFERENCES User(user_id) - ); - - CREATE TABLE Profile ( - profile_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - bio TEXT, - user_id INTEGER NOT NULL, - FOREIGN KEY (user_id) REFERENCES User(user_id) - ); - ``` + + ```sql + CREATE TABLE User ( + user_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name VARCHAR(255), + email VARCHAR(255) UNIQUE NOT NULL + ); + + CREATE TABLE Post ( + post_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + title VARCHAR(255) NOT NULL, + content TEXT, + author_id INTEGER, + FOREIGN KEY (author_id) REFERENCES User(user_id) + ); + + CREATE TABLE Profile ( + profile_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + bio TEXT, + user_id INTEGER NOT NULL, + FOREIGN KEY (user_id) REFERENCES User(user_id) + ); + ``` + 1. Run the following command to create your SQLite database file from `schema.sql`: - ``` - sqlite3 hello-prisma.db < schema.sql - ``` + ``` + sqlite3 hello-prisma.db < schema.sql + ``` 1. Add a `generator` to the Prisma schema to be able to generate Prisma Client: - ```prisma - generator client { - provider = "prisma-client-js" - } - ``` + ```prisma + generator client { + provider = "prisma-client-js" + } + ``` 1. Configure project (TypeScript): - ``` - npm init -y - npm install typescript ts-node prisma2 --save-dev - npm install @prisma/client - ``` + ``` + npm init -y + npm install typescript ts-node prisma2 --save-dev + npm install @prisma/client + ``` 1. Run `npx prisma2 introspect` to introspect your database and add your models to the Prisma schema 1. Run `npx prisma2 generate` to generate Prisma Client 1. Run `touch tsconfig.json` and the following contents to it: - ```json - { - "compilerOptions": { - "sourceMap": true, - "outDir": "dist", - "strict": true, - "lib": ["esnext", "dom"], - "esModuleInterop": true - } - } - ``` + ```json + { + "compilerOptions": { + "sourceMap": true, + "outDir": "dist", + "strict": true, + "lib": ["esnext", "dom"], + "esModuleInterop": true + } + } + ``` 1. Run `touch index.ts` to create a source file and add the following code: - ```ts - import { PrismaClient } from '@prisma/client' - - const prisma = new PrismaClient() - - // A `main` function so that we can use async/await - async function main() { - const user1 = await prisma.user.create({ - data: { - email: 'alice@prisma.io', - name: 'Alice', - post: { - create: { - title: 'Watch the talks from Prisma Day 2019', - content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', - }, - }, - }, - include: { - post: true, - }, - }) - console.log(user1) - } - - main() - .catch(e => console.error(e)) - .finally(async () => { - await prisma.disconnect() - }) - ``` -1. Run `npx ts-node index.ts` to execute the script + ```ts + import { PrismaClient } from "@prisma/client"; + + const prisma = new PrismaClient(); + + // A `main` function so that we can use async/await + async function main() { + const user1 = await prisma.user.create({ + data: { + email: "alice@prisma.io", + name: "Alice", + post: { + create: { + title: "Watch the talks from Prisma Day 2019", + content: "https://www.prisma.io/blog/z11sg6ipb3i1/", + }, + }, + }, + include: { + post: true, + }, + }); + console.log(user1); + } + + main() + .catch(e => console.error(e)) + .finally(async () => { + await prisma.disconnect(); + }); + ``` + +1. Run `npx ts-node index.ts` to execute the script diff --git a/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx b/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx index 3184f33272..891eecae94 100644 --- a/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx +++ b/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx @@ -1,10 +1,9 @@ --- - title: "Start from scratch (Prisma Migrate)" - metaTitle: "" - metaDescription: "" +title: "Start from scratch (Prisma Migrate)" +metaTitle: "" +metaDescription: "" --- - ## Overview **Note: The content of this page is temporary and will be updated soon.** @@ -19,98 +18,102 @@ Follow these steps for an initial Prisma setup: 1. Run `cd hello-prisma` to navigate into it 1. Run `touch schema.prisma` to create an empty [Prisma schema](../../prisma-schema-file.md) 1. Add a `datasource` to the Prisma schema and set your database connection string as the `url`, e.g.: - ```prisma - datasource db { - provider = "postgresql" - url = "postgresql://janedoe:janedoe@localhost:5432/hello-prisma" - } - ``` + ```prisma + datasource db { + provider = "postgresql" + url = "postgresql://janedoe:janedoe@localhost:5432/hello-prisma" + } + ``` 1. Add your models to the Prisma schema, e.g.: - ```prisma - model Post { - post_id Int @id @default(autoincrement()) - content String? - title String - author User? - } - model Profile { - profile_id Int @id @default(autoincrement()) - bio String? - user User - } + ```prisma + model Post { + post_id Int @id @default(autoincrement()) + content String? + title String + author User? + } + + model Profile { + profile_id Int @id @default(autoincrement()) + bio String? + user User + } + + model User { + user_id Int @id @default(autoincrement()) + email String @unique + name String? + posts Post[] + profiles Profile[] + } + ``` - model User { - user_id Int @id @default(autoincrement()) - email String @unique - name String? - posts Post[] - profiles Profile[] - } - ``` 1. Add a `generator` to the Prisma schema to be able to generate Prisma Client: - ```prisma - generator client { - provider = "prisma-client-js" - } - ``` + ```prisma + generator client { + provider = "prisma-client-js" + } + ``` 1. Run the following commands to configure your project (TypeScript): - ``` - npm init -y - npm install typescript ts-node prisma2 @types/node --save-dev - npm install @prisma/client - ``` + ``` + npm init -y + npm install typescript ts-node prisma2 @types/node --save-dev + npm install @prisma/client + ``` 1. Run `touch tsconfig.json` and the following contents to it: - ```json - { - "compilerOptions": { - "sourceMap": true, - "outDir": "dist", - "strict": true, - "lib": ["esnext"], - "esModuleInterop": true - } - } - ``` + ```json + { + "compilerOptions": { + "sourceMap": true, + "outDir": "dist", + "strict": true, + "lib": ["esnext"], + "esModuleInterop": true + } + } + ``` 1. Migrate your database by running the following commands: - ``` - npx prisma2 migrate save --name 'init' --experimental - npx prisma2 migrate up --experimental - ``` + ``` + npx prisma2 migrate save --name 'init' --experimental + npx prisma2 migrate up --experimental + ``` 1. Generate Prisma Client based on your data model with the following command: ``` npx prisma2 generate ``` 1. Run `touch index.ts` to create a source file and add the following code: - ```ts - import { PrismaClient } from '@prisma/client' - const prisma = new PrismaClient() + ```ts + import { PrismaClient } from "@prisma/client"; - // A `main` function so that we can use async/await - async function main() { - const user1 = await prisma.user.create({ - data: { - email: 'alice@prisma.io', - name: 'Alice', - posts: { - create: { - title: 'Watch the talks from Prisma Day 2019', - content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', - }, - }, - }, - include: { - posts: true, - }, - }) - console.log(user1) - } + const prisma = new PrismaClient(); + + // A `main` function so that we can use async/await + async function main() { + const user1 = await prisma.user.create({ + data: { + email: "alice@prisma.io", + name: "Alice", + posts: { + create: { + title: "Watch the talks from Prisma Day 2019", + content: "https://www.prisma.io/blog/z11sg6ipb3i1/", + }, + }, + }, + include: { + posts: true, + }, + }); + console.log(user1); + } + + main() + .catch(e => console.error(e)) + .finally(async () => { + await prisma.disconnect(); + }); + ``` - main() - .catch(e => console.error(e)) - .finally(async () => { - await prisma.disconnect() - }) - ``` 1. Run `npx ts-node index.ts` to execute the script diff --git a/content/01-getting-started/03-setup-prisma/index.mdx b/content/01-getting-started/03-setup-prisma/index.mdx index 0ab1288099..8d5c42d18d 100644 --- a/content/01-getting-started/03-setup-prisma/index.mdx +++ b/content/01-getting-started/03-setup-prisma/index.mdx @@ -1,6 +1,6 @@ --- - title: "Setup Prisma" - metaTitle: "" - metaDescription: "" - duration: "15 min" ---- \ No newline at end of file +title: "Setup Prisma" +metaTitle: "" +metaDescription: "" +duration: "15 min" +--- diff --git a/content/01-getting-started/index.mdx b/content/01-getting-started/index.mdx index b26193a246..3d9a0c5135 100644 --- a/content/01-getting-started/index.mdx +++ b/content/01-getting-started/index.mdx @@ -1,5 +1,5 @@ --- - title: "Getting started" - metaTitle: "Getting started" - metaDescription: "Getting started" ---- \ No newline at end of file +title: "Getting started" +metaTitle: "Getting started" +metaDescription: "Getting started" +--- diff --git a/content/02-understand-prisma/01-introduction.mdx b/content/02-understand-prisma/01-introduction.mdx index 9c336ee16b..423503d698 100644 --- a/content/02-understand-prisma/01-introduction.mdx +++ b/content/02-understand-prisma/01-introduction.mdx @@ -1,7 +1,7 @@ --- - title: "Introduction" - metaTitle: "" - metaDescription: "" +title: "Introduction" +metaTitle: "" +metaDescription: "" --- -Coming 🔜 \ No newline at end of file +Coming 🔜 diff --git a/content/02-understand-prisma/02-features.mdx b/content/02-understand-prisma/02-features.mdx index 72e81f810e..f478b646b0 100644 --- a/content/02-understand-prisma/02-features.mdx +++ b/content/02-understand-prisma/02-features.mdx @@ -1,7 +1,7 @@ --- - title: "Features" - metaTitle: "" - metaDescription: "" +title: "Features" +metaTitle: "" +metaDescription: "" --- **Note: The content of this page is still in progress.** @@ -70,12 +70,12 @@ Algorithm option (MySQL): Lock option (MySQL): -| Index type (Algorithm) | MySQL | ◭ Prisma schema | ◭ Prisma Migrate | ◭ Prisma Client | -| ---------------------- | ----- | --------------- | ---------------- | --------------- | -| `NONE` | Yes | Not yet | Not yet | Yes | -| `EXCLUSIVE` | Yes | Not yet | Not yet | Yes | -| `SHARED` | Yes | Not yet | Not yet | Yes | - | Yes (e.g. via `date('now')`) | +| Index type (Algorithm) | MySQL | ◭ Prisma schema | ◭ Prisma Migrate | ◭ Prisma Client | +| ---------------------------- | ----- | --------------- | ---------------- | --------------- | +| `NONE` | Yes | Not yet | Not yet | Yes | +| `EXCLUSIVE` | Yes | Not yet | Not yet | Yes | +| `SHARED` | Yes | Not yet | Not yet | Yes | +| Yes (e.g. via `date('now')`) | ### Misc @@ -89,8 +89,6 @@ Lock option (MySQL): | JSON support | Yes | No | No | Not yet | Not yet | Not yet | | Fuzzy/Phrase Full Text Search | Yes | Yes | No | Not yet | Not yet | Not yet | - - ## Functions | Name | PostgreSQL | MySQL | SQLite | @@ -98,7 +96,8 @@ Lock option (MySQL): | `uuid()` | Yes (via an [extension](http://www.ossp.org/pkg/lib/uuid/)) | Yes (but usage as default values only in [MySQL 8 and higher](https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html)) | No | | `cuid()` | No | No | No | | `autoincrement()` | Yes (via the `SERIAL` type) | Yes (via the `AUTO_INCREMENT` keyword) | Yes (via the `AUTOINCREMENT` keyword) | -| `now()` | Yes | Yes +| `now()` | Yes | Yes | + ## Type mappings between Prisma and database TBD for different scenarios: diff --git a/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx b/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx index 86c951be1b..22e4d56063 100644 --- a/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx +++ b/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx @@ -1,6 +1,5 @@ --- - title: "How Prisma fits into your stack" - metaTitle: "How Prisma fits into your stack" - metaDescription: "How Prisma fits into your stack" +title: "How Prisma fits into your stack" +metaTitle: "How Prisma fits into your stack" +metaDescription: "How Prisma fits into your stack" --- - diff --git a/content/02-understand-prisma/04-is-prisma-an-orm.mdx b/content/02-understand-prisma/04-is-prisma-an-orm.mdx index 0dd377124c..d8f3a1d5b9 100644 --- a/content/02-understand-prisma/04-is-prisma-an-orm.mdx +++ b/content/02-understand-prisma/04-is-prisma-an-orm.mdx @@ -1,12 +1,11 @@ --- - title: "Is Prisma an ORM?" - metaTitle: "" - metaDescription: "" +title: "Is Prisma an ORM?" +metaTitle: "" +metaDescription: "" --- ## Overview - To answer the question briefly: _No, Prisma is not an ORM_. If you're looking for an Object-Relational-Mapper (ORM), Prisma may help you. While Prisma shares the same goals with ORMs, it takes a different approach. @@ -137,10 +136,10 @@ Model instances represent database records and contain three important things: You can fetch and update a model instance with Sequelize as follows: ```js -const ada = await User.findOne({ where: { firstName: 'Ada' } }) -ada.lastName = 'Lovelace' -await ada.save() -ada.getFullName() // Ada Lovelace +const ada = await User.findOne({ where: { firstName: "Ada" } }); +ada.lastName = "Lovelace"; +await ada.save(); +ada.getFullName(); // Ada Lovelace ``` #### Schema migrations @@ -159,39 +158,39 @@ Assuming you were starting from scratch, this is what a full workflow would look // migrations/20191217102908-create-user.js module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.createTable('Users', { + return queryInterface.createTable("Users", { id: { allowNull: false, autoIncrement: true, primaryKey: true, - type: Sequelize.INTEGER + type: Sequelize.INTEGER, }, firstName: { type: Sequelize.STRING, - field: 'first_name' + field: "first_name", }, lastName: { type: Sequelize.STRING, - field: 'last_name' + field: "last_name", }, email: { - type: Sequelize.STRING + type: Sequelize.STRING, }, emailConfirmed: { type: Sequelize.BOOLEAN, - field: 'email_confirmed', + field: "email_confirmed", allowNull: false, - defaultValue: false + defaultValue: false, }, birthDate: { - type: Sequelize.DATE - } - }) + type: Sequelize.DATE, + }, + }); }, down: (queryInterface, Sequelize) => { - return queryInterface.dropTable('Users') - } -} + return queryInterface.dropTable("Users"); + }, +}; ``` 2. Create the corresponding model as in the previous section. diff --git a/content/02-understand-prisma/05-data-modeling.mdx b/content/02-understand-prisma/05-data-modeling.mdx index 6c1ab79dbe..c162506025 100644 --- a/content/02-understand-prisma/05-data-modeling.mdx +++ b/content/02-understand-prisma/05-data-modeling.mdx @@ -1,7 +1,7 @@ --- - title: "Data modeling" - metaTitle: "" - metaDescription: "" +title: "Data modeling" +metaTitle: "" +metaDescription: "" --- ## What is data modeling? @@ -70,10 +70,10 @@ There often is a strong correlation between the tables in your database and the ```js class User { constructor(user_id, name, email, isAdmin) { - this.user_id = user_id - this.name = name - this.email = email - this.isAdmin = isAdmin + this.user_id = user_id; + this.name = name; + this.email = email; + this.isAdmin = isAdmin; } } ``` @@ -94,14 +94,9 @@ Notice how the `User` model in both cases has the same properties as the `users` With this setup, you can retrieve records from the `users` table and store them instances of your `User` type. The following example code snippet uses [`pg`](https://node-postgres.com/) as the driver for PostgreSQL and creates a `User` instance based on the above defined JavaScript class: ```js -const resultRows = await client.query('SELECT * FROM users WHERE user_id = 1') -const userData = resultRows[0] -const user = new User( - userData.user_id, - userData.name, - userData.email, - userData.isAdmin, -) +const resultRows = await client.query("SELECT * FROM users WHERE user_id = 1"); +const userData = resultRows[0]; +const user = new User(userData.user_id, userData.name, userData.email, userData.isAdmin); // user = { // user_id: 1, // name: "Alice", @@ -138,8 +133,8 @@ User.init( }, isAdmin: Sequelize.BOOLEAN, }, - { sequelize, modelName: 'user' }, -) + { sequelize, modelName: "user" } +); ``` To get an example with this `User` class to work, you still need to create the corresponding table in the database. With Sequelize, you have two ways of doing this: @@ -150,7 +145,7 @@ To get an example with this `User` class to work, you still need to create the c Note that you'll never instantiate the `User` class manually (using `new User(...)`) as was shown in the previous section, but rather call _static_ methods on the `User` class which then return the `User` model instances: ```js -const user = await User.findByPk(42) +const user = await User.findByPk(42); ``` The call to `findByPk` creates a SQL statement to retrieve the `User` record that's identified by the ID value `42`. @@ -183,10 +178,10 @@ Prisma Client JS uses TypeScript [type aliases](http://www.typescriptlang.org/do ```ts export declare type User = { - id: number; - name: string | null; - email: string; - isAdmin: boolean; + id: number; + name: string | null; + email: string; + isAdmin: boolean; }; ``` @@ -194,7 +189,7 @@ Addtionally to the generated types, Prisma Client also provides a data access AP ```js import { PrismaClient } from '@prisma/client' -// or +// or // const { PrismaClient } = require('@prisma/client') const prisma = new PrismaClient() diff --git a/content/02-understand-prisma/index.mdx b/content/02-understand-prisma/index.mdx index eb0bd30890..52da02da2d 100644 --- a/content/02-understand-prisma/index.mdx +++ b/content/02-understand-prisma/index.mdx @@ -1,6 +1,5 @@ --- - title: "Understand Prisma" - metaTitle: "Understand Prisma" - metaDescription: "Understand Prisma" +title: "Understand Prisma" +metaTitle: "Understand Prisma" +metaDescription: "Understand Prisma" --- - diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx index 46eddf8145..cc68452de2 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx @@ -79,7 +79,7 @@ Syntax highlighting for PSL is available via a [VS Code extension](https://marke PSL code snippets on GitHub can be rendered with syntax highlighting as well by using the `.prisma` file extension or annotating fenced code blocks in Markdown with `prisma`: -~~~ +```` ```prisma model User { id Int @id @default(autoincrement()) @@ -88,7 +88,7 @@ model User { name String? } ``` -~~~ +```` ## Using environment variables @@ -126,9 +126,9 @@ Prisma provides native support for `.env` files **if the `.env` file is located └── schema.prisma ``` -This means any environment variables defined in that `.env` file will automatically be loaded when running a Prisma CLI command. +This means any environment variables defined in that `.env` file will automatically be loaded when running a Prisma CLI command. -> **WARNING**: Do not commit your `.env` files into version control. +> **WARNING**: Do not commit your `.env` files into version control. For example, it is a common scenario to set your database connection URL via an environment variable: @@ -152,10 +152,10 @@ When running any command that needs to access the database defined via the `data If you want environment variables to be evaluated at runtime, you need to load them manually in your application code, e.g. using [`dotenv`](https://github.com/motdotla/dotenv): ```ts -import * as dotenv from 'dotenv' +import * as dotenv from "dotenv"; -dotenv.config() // load the environment variables -console.log(`The connection URL is ${process.env.DATABASE_URL}`) +dotenv.config(); // load the environment variables +console.log(`The connection URL is ${process.env.DATABASE_URL}`); ``` ## Comments @@ -194,4 +194,4 @@ Similar to tools like [gofmt](https://golang.org/cmd/gofmt/) and [prettier](http Like `gofmt` and unlike `prettier`, there are no options for configuration here. **There is exactly one way to format a prisma file**. -Learn more about the formatting rules in the [spec](https://github.com/prisma/specs/tree/master/schema#formatting-rules). \ No newline at end of file +Learn more about the formatting rules in the [spec](https://github.com/prisma/specs/tree/master/schema#formatting-rules). diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx index c485b17a47..2701762e9d 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx @@ -1,7 +1,7 @@ --- -title: 'Connectors' -metaTitle: '' -metaDescription: '' +title: "Connectors" +metaTitle: "" +metaDescription: "" --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx index f6c4410596..19bf29a7fd 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx @@ -152,4 +152,4 @@ This example shows how to use a custom generator that's located in a directory c generator client { provider = "./my-generator" } -``` \ No newline at end of file +``` diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx index aea03632fa..41bd8269c7 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx @@ -1,14 +1,14 @@ --- - title: "Models" - metaTitle: "" - metaDescription: "" +title: "Models" +metaTitle: "" +metaDescription: "" --- ## Overview This is an extension of the [Data model]() page that discusses _models_ in the data model definition in detail. -Models represent the entities of your application domain. They are defined using `model` blocks in the data model. In the [example data model](), `User`, `Profile`, `Post` and `Category` are models. Here's the `User` model from the example on the again for reference: +Models represent the entities of your application domain. They are defined using `model` blocks in the data model. In the [example data model](), `User`, `Profile`, `Post` and `Category` are models. Here's the `User` model from the example on the again for reference: ```prisma model User { @@ -184,10 +184,10 @@ Here is an example illustrating the use of a `user` property from the Prisma Cli ```js const newUser = await prisma.user.create({ data: { - name: 'Alice', + name: "Alice", }, -}) -const allUsers = await prisma.user.findMany() +}); +const allUsers = await prisma.user.findMany(); ``` ### Type definitions @@ -200,11 +200,11 @@ For example, the type definition for the `User` model from above would look as f ```ts export type User = { - id: number - email: string - name: string | null - role: string -} + id: number; + email: string; + name: string | null; + role: string; +}; ``` Note that the relation fields `posts` and `profile` are not included in the type definion by default. However, if you need variations of the `User` type you can still define them using some of [Prisma Client's generated helper types]() (in this case, these helper types would be called `UserGetIncludePayload` and `UserGetSelectPayload`). diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx index c867819d9c..1837d1556a 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx @@ -1,7 +1,7 @@ --- - title: "Relations" - metaTitle: "" - metaDescription: "" +title: "Relations" +metaTitle: "" +metaDescription: "" --- ## Overview @@ -555,7 +555,7 @@ CREATE INDEX "_CategoryToPost_B_index" ON "_CategoryToPost"("B" int4_ops); ![](https://imgur.com/DQClFIX.png) -An _explicit_ variant of a similar m-n-relation would define an extra model to represent a relation table. In this case, you can also attach additional information to the relation (such as the point in time when it was created): +An _explicit_ variant of a similar m-n-relation would define an extra model to represent a relation table. In this case, you can also attach additional information to the relation (such as the point in time when it was created): ```prisma model Category { @@ -647,7 +647,6 @@ There further must be a unique index defined on both foreign key columns: CREATE UNIQUE INDEX "_CategoryToPost_AB_unique" ON "_CategoryToPost"("A" int4_ops,"B" int4_ops); ``` - ## Self-relations A relation field can also reference its own model, in this case the relation is called a _self-relation_. Self-relations can be of any cardinality, 1-1, 1-n and m-n. diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx index 8b7b4c3b30..b0faddb77a 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx @@ -1,6 +1,6 @@ --- - title: "Schema" - metaTitle: "" - metaDescription: "" - experimental: true ---- \ No newline at end of file +title: "Schema" +metaTitle: "" +metaDescription: "" +experimental: true +--- diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx index 343bb28f9f..8a9dd1a5f2 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx @@ -11,19 +11,19 @@ Prisma Client is an auto-generated database client that's tailored to your datab Generating Prisma Client requires three steps: 1. Add the following `generator` definition to your Prisma schema: - ```prisma - generator client { - provider = "prisma-client-js" - } - ``` + ```prisma + generator client { + provider = "prisma-client-js" + } + ``` 1. Install the `@prisma/client` npm module: - ``` - npm install @prisma/client - ``` + ``` + npm install @prisma/client + ``` 1. Generate Prisma Client with the following comand: - ``` - prisma generate - ``` + ``` + prisma generate + ``` **Important**: You need to re-execute the `prisma generate` command after every change that's made to your Prisma schema to update the generated Prisma Client code. @@ -36,18 +36,18 @@ Note also that `prisma generate` is _automatically_ invoked when you're installi Once generated, you can import and instantiate Prisma Client in your code as follows: ```js -import { PrismaClient } from '@prisma/client' +import { PrismaClient } from "@prisma/client"; -const prisma = new PrismaClient() +const prisma = new PrismaClient(); // use `prisma` in your application to read and write data in your DB ``` or ```js -const { PrismaClient } = require('@prisma/client') +const { PrismaClient } = require("@prisma/client"); -const prisma = new PrismaClient() +const prisma = new PrismaClient(); // use `prisma` in your application to read and write data in your DB ``` @@ -59,7 +59,7 @@ The `@prisma/client` node module is different from "conventional" node modules. As an example for such a module, consider the [`lodash`](https://lodash.com/) npm module. When you install it with `npm install lodash`, it gets downloaded and stored into `node_modules/lodash`. This `node_modules/lodash` directory doesn't change unless another `npm install` is invoked at some point (e.g. when an update of the package is available). -The `@prisma/client` node module is different. It is a "facade package" (basically a stub) that doesn't contain any functional code, such as types or the Prisma Client runtime. +The `@prisma/client` node module is different. It is a "facade package" (basically a stub) that doesn't contain any functional code, such as types or the Prisma Client runtime. While you do need to install it _once_ with `npm install @prisma/client`, it is likely that the code inside the `node_modules/@prisma/client` directory changes more often as you're evolving your application. This is because the directory contains code that is _generated_ based on your Prisma schema. When your Prisma schema changes (e.g. because you perform a [schema migration]()), you need to re-execute `prisma generate` which takes care of updating the code in `node_modules/@prisma/client` so that it reflects the schema changes. @@ -71,7 +71,7 @@ Because the `node_modules/@prisma/client` directory contains some code that is _ The "facade package" is necessary to enable typical build and deployment workflows of Node.js applications. Here are a few examples for this: -- This workflow allows teams to follow conventional practices for version control (because developers can clone repositories, run `npm install` and have the repo be ready without an extra step of running `prisma generate`). +- This workflow allows teams to follow conventional practices for version control (because developers can clone repositories, run `npm install` and have the repo be ready without an extra step of running `prisma generate`). - The facade package ensures that Prisma Client survives the [pruning](https://docs.npmjs.com/cli/prune.html) that's often employed by Node.js package managers. ## Specifying the target location for Prisma Client @@ -121,9 +121,9 @@ After running `prisma generate` for that schema file, the Prisma Client package By generating Prisma Client into `node_modules/@prisma/client`, you can import it and instantiate it in your code as follows: ```js -import { PrismaClient } from '@prisma/client' +import { PrismaClient } from "@prisma/client"; -const prisma = new PrismaClient() +const prisma = new PrismaClient(); // use `prisma` in your application to read and write data in your DB ``` @@ -131,9 +131,9 @@ const prisma = new PrismaClient() or ```js -const { PrismaClient } = require('@prisma/client') +const { PrismaClient } = require("@prisma/client"); -const prisma = new PrismaClient() +const prisma = new PrismaClient(); // use `prisma` in your application to read and write data in your DB ``` @@ -147,4 +147,3 @@ By generating Prisma Client into `node_modules`, the query engine is kept out of ## Generating Prisma Client in the `postinstall` hook of `@prisma/client` The `@prisma/client` package defines its own `postinstall` hook that's being executed whenever the package is being installed. This hook invokes the `prisma generate` command which in turn generates the Prisma Client code into the default location `node_modules/@prisma/client`. Notice that this requires the `prisma` CLI to be available, either as local dependency or as a global installation (it is recommended to always install the `prisma` package as a development dependency, using `npm install prisma --save-dev`, to avoid versioning conflicts though). - diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx index ccb7df6817..76ca9bcde7 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx @@ -25,12 +25,12 @@ CREATE TABLE posts ( created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, title VARCHAR(256) NOT NULL, content TEXT, - author_id INTEGER REFERENCES users(user_id) + author_id INTEGER REFERENCES users(user_id) ); CREATE TABLE profiles ( profile_id SERIAL PRIMARY KEY NOT NULL, bio TEXT, - user_id INTEGER NOT NULL UNIQUE REFERENCES users(user_id) + user_id INTEGER NOT NULL UNIQUE REFERENCES users(user_id) ); CREATE TABLE categories ( category_id SERIAL PRIMARY KEY NOT NULL, @@ -150,23 +150,25 @@ The current naming of relation fields can also lead to confusion in the Prisma C // Nested writes const profile = await prisma.profiles.create({ data: { - bio: 'Hello World', + bio: "Hello World", user_id: { create: { - name: 'Alice', - email: 'alice@prisma.io' - } - } - } -}) + name: "Alice", + email: "alice@prisma.io", + }, + }, + }, +}); // Fluent API -const userByProfile = await prisma.profiles.findOne({ - where: { id: 1 } -}).user_id() +const userByProfile = await prisma.profiles + .findOne({ + where: { id: 1 }, + }) + .user_id(); ``` -In both cases, `user_id` is used to refer to an _entire_ "user object", not only to the `user_id` column. +In both cases, `user_id` is used to refer to an _entire_ "user object", not only to the `user_id` column. ## Using `@map` and `@@map` to rename fields and models in the Prisma Client API @@ -220,20 +222,22 @@ With these changes, you're now adhering to Prisma's naming conventions and the g // Nested writess const profile = await prisma.profile.create({ data: { - bio: 'Hello World', + bio: "Hello World", user: { create: { - name: 'Alice', - email: 'alice@prisma.io' - } - } - } -}) + name: "Alice", + email: "alice@prisma.io", + }, + }, + }, +}); // Fluent API -const userByProfile = await prisma.profile.findOne({ - where: { id: 1 } -}).user() +const userByProfile = await prisma.profile + .findOne({ + where: { id: 1 }, + }) + .user(); ``` -> **Warning**: `@map` and `@@map` attributes are removed when you run `prisma introspect` again. You might want to back up your Prisma schema with these attributes in order to not having to annotate everything from scratch again after a re-introspection. \ No newline at end of file +> **Warning**: `@map` and `@@map` attributes are removed when you run `prisma introspect` again. You might want to back up your Prisma schema with these attributes in order to not having to annotate everything from scratch again after a re-introspection. diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx index 339acdd12c..04480f144d 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx @@ -45,7 +45,7 @@ Consider the following example `findOne` invocation: ```ts const result = await prisma.user.findOne({ where: { id: 1 }, -}) +}); ``` The `result` of this API call is a plain old JavaScript object that might look similar to this: @@ -92,7 +92,7 @@ const result = await prisma.user.findMany({ }, }, }, -}) +}); ``` And the following one is not allowed because `select` and `include` appear on the same level of nesting right next to each other: @@ -106,7 +106,7 @@ const result = await prisma.user.findMany({ include: { posts: true, }, -}) +}); ``` This case would be caught with the following exceptions: @@ -149,42 +149,42 @@ The type of the `select` option is custom for each model. For example, for the ` ```ts export type UserSelect = { - id?: boolean - name?: boolean - email?: boolean - role?: boolean - coinflips?: boolean - profileViews?: boolean - posts?: boolean | FindManyPostArgs -} + id?: boolean; + name?: boolean; + email?: boolean; + role?: boolean; + coinflips?: boolean; + profileViews?: boolean; + posts?: boolean | FindManyPostArgs; +}; export type PostSelect = { - id?: boolean - title?: boolean - published?: boolean - author?: boolean | UserArgs -} + id?: boolean; + title?: boolean; + published?: boolean; + author?: boolean | UserArgs; +}; ``` The types also contain relation fields which can be even further controlled with specific arguments: ```ts export type UserArgs = { - select?: UserSelect | null - include?: UserInclude | null -} + select?: UserSelect | null; + include?: UserInclude | null; +}; export type FindManyPostArgs = { - select?: PostSelect | null - include?: PostInclude | null - where?: PostWhereInput | null - orderBy?: PostOrderByInput | null - skip?: number | null - after?: PostWhereUniqueInput | null - before?: PostWhereUniqueInput | null - first?: number | null - last?: number | null -} + select?: PostSelect | null; + include?: PostInclude | null; + where?: PostWhereInput | null; + orderBy?: PostOrderByInput | null; + skip?: number | null; + after?: PostWhereUniqueInput | null; + before?: PostWhereUniqueInput | null; + first?: number | null; + last?: number | null; +}; ``` You can read more about the additional types on `FindManyPostArgs` [here](). @@ -200,7 +200,7 @@ const result = await prisma.user.findOne({ name: true, profileViews: true, }, -}) +}); ``` The `result` object now looks as follows: @@ -220,22 +220,22 @@ const result = await prisma.user.findMany({ email: true, role: true, }, -}) +}); ``` Since `findMany` returns an array of objects, `result` would now look as follows: ```js -;[ +[ { - email: 'alice@prisma.io', - role: 'ADMIN', + email: "alice@prisma.io", + role: "ADMIN", }, { - email: 'bob@prisma.io', - role: 'USER', + email: "bob@prisma.io", + role: "USER", }, -] +]; ``` Here's how you can include additional fields of a relation: @@ -252,27 +252,27 @@ const result = await prisma.user.findMany({ }, }, }, -}) +}); ``` In this case, the result might look as follow: ```ts -;[ +[ { id: 1, - name: 'Alice', + name: "Alice", posts: [ - { id: 1, title: 'Hello World' }, - { id: 2, title: 'Bye bye' }, + { id: 1, title: "Hello World" }, + { id: 2, title: "Bye bye" }, ], }, { id: 2, - name: 'Bob', + name: "Bob", posts: [], }, -] +]; ``` You can also nest the `include` option inside of the `select` option: @@ -288,7 +288,7 @@ const result = await prisma.user.findMany({ }, }, }, -}) +}); ``` This would result in the following structure for the `result` object: @@ -297,37 +297,37 @@ This would result in the following structure for the `result` object: [ { id: 1, - name: 'Alice', + name: "Alice", posts: [ { id: 1, - title: 'Hello World', + title: "Hello World", published: true, author: { id: 1, - name: 'Alice', - email: 'alice@prisma.io', - role: 'ADMIN', + name: "Alice", + email: "alice@prisma.io", + role: "ADMIN", coinflips: [true, false], profileViews: 0, }, }, { id: 2, - title: 'Bye bye', + title: "Bye bye", published: false, author: { id: 1, - name: 'Alice', - email: 'alice@prisma.io', - role: 'USER', + name: "Alice", + email: "alice@prisma.io", + role: "USER", coinflips: [], profileViews: 0, }, }, ], }, -] +]; ``` Note that the `author` contains all fields of the `User` model's default selection set (scalars, arrays/scalar lists, enums). @@ -342,33 +342,33 @@ The type of the `include` option is custom for each model. For example, for the ```ts export type UserInclude = { - posts?: boolean | FindManyPostArgs -} + posts?: boolean | FindManyPostArgs; +}; export type PostInclude = { - author?: boolean | UserArgs -} + author?: boolean | UserArgs; +}; ``` The types contain only relation fields which can be even further controlled with specific arguments: ```ts export type UserArgs = { - select?: UserSelect | null - include?: UserInclude | null -} + select?: UserSelect | null; + include?: UserInclude | null; +}; export type FindManyPostArgs = { - select?: PostSelect | null - include?: PostInclude | null - where?: PostWhereInput | null - orderBy?: PostOrderByInput | null - skip?: number | null - after?: PostWhereUniqueInput | null - before?: PostWhereUniqueInput | null - first?: number | null - last?: number | null -} + select?: PostSelect | null; + include?: PostInclude | null; + where?: PostWhereInput | null; + orderBy?: PostOrderByInput | null; + skip?: number | null; + after?: PostWhereUniqueInput | null; + before?: PostWhereUniqueInput | null; + first?: number | null; + last?: number | null; +}; ``` You can read more about the additional types on `FindManyPostArgs` [here](). @@ -379,7 +379,7 @@ You can read more about the additional types on `FindManyPostArgs` [here](). const result = await prisma.user.findOne({ where: { id: 1 }, include: { posts: true }, -}) +}); ``` The `result` object in this case contains the [default selection set]() of the `User` model _plus_ its `posts` relation: @@ -416,12 +416,12 @@ const result = await prisma.user.findOne({ posts: { select: { published: true, - title: true - } - } - } -}) -``` + title: true, + }, + }, + }, +}); +``` This would lead to the following structure of the `result` object: @@ -446,7 +446,6 @@ This would lead to the following structure of the `result` object: } ``` - The nesting and combinations can be arbitrarily deep: ```ts @@ -462,15 +461,15 @@ const result = await prisma.user.findOne({ id: true, posts: { select: { - title: true - } - } - } - } - } - } - } -}) + title: true, + }, + }, + }, + }, + }, + }, + }, +}); ``` In this case, the `result` object would look as follows: @@ -516,4 +515,4 @@ In this case, the `result` object would look as follows: } ] } -``` \ No newline at end of file +``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx index 28ed1f570b..60fda8d5b4 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx @@ -9,16 +9,16 @@ metaDescription: "" You can send raw SQL queries to your database using the `raw` function that's exposed by your `PrismaClient` instance. It returns the query results as plain old JavaScript objects: ```ts -const result = await prisma.raw('SELECT * FROM User;') +const result = await prisma.raw("SELECT * FROM User;"); ``` `result` is an array where each object corresponds to a retrieved database record: ```js [ - { "id":1, "email":"sarah@prisma.io", "name":"Sarah" }, - { "id":2, "email":"alice@prisma.io", "name":"Alice" } -] + { id: 1, email: "sarah@prisma.io", name: "Sarah" }, + { id: 2, email: "alice@prisma.io", name: "Alice" }, +]; ``` ## Tagged templates @@ -26,7 +26,7 @@ const result = await prisma.raw('SELECT * FROM User;') The `raw` method is implemented as a [tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates). Therefore, you can also call `raw` as follows: ```ts -const result = await prisma.raw`SELECT * FROM User;` +const result = await prisma.raw`SELECT * FROM User;`; ``` ## Setting variables @@ -34,8 +34,8 @@ const result = await prisma.raw`SELECT * FROM User;` To include variables in your SQL query, you can use JavaScript string interpolation with [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals): ```ts -const userId = 42 -const result = await prisma.raw`SELECT * FROM User WHERE id = ${userId};` +const userId = 42; +const result = await prisma.raw`SELECT * FROM User WHERE id = ${userId};`; ``` ## Typing `raw` results @@ -50,9 +50,9 @@ The return type of `raw` is a `Promise` for the [generic](https://www.typescript ```ts // import the generated `User` type from the `@prisma/client` module -import { User } from '@prisma/client' +import { User } from "@prisma/client"; -const result = await prisma.raw('SELECT * FROM User;') +const result = await prisma.raw("SELECT * FROM User;"); // result is of type: `User[]` ``` @@ -62,4 +62,4 @@ Now, `result` is statically typed to the generated `User` type (or rather an arr If you're selecting only specific fields of the model or want to include relations, read the documentation about [leveraging Prisma Client's generated types](./generated-types.md) if you want to ensure that the query results are properly typed. -Note that calls to `SELECT` always return arrays of type `T`, but other SQL operations (like `INSERT` or `UPDATE`) might return single objects. \ No newline at end of file +Note that calls to `SELECT` always return arrays of type `T`, but other SQL operations (like `INSERT` or `UPDATE`) might return single objects. diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx index 29ffaa85dc..66b60e77aa 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx @@ -16,10 +16,10 @@ Unless you want to employ a specific optimization, calling `prisma.connect()` is If you need the first request to respond instantly and can't wait for the lazy connection to be established, you can explicitly call `prisma.connect()` to establish a connection to the Prisma data source: ```ts -const prisma = new PrismaClient() +const prisma = new PrismaClient(); // run inside `async` function -await prisma.connect() +await prisma.connect(); ``` **IMPORTANT**: It is recommended to always explicitly call `prisma.disconnect()` in your code. Also, be sure to disconnect even when an exception is thrown: @@ -27,16 +27,16 @@ await prisma.connect() ```ts main() .catch(e => { - throw e + throw e; }) .finally(async () => { - await prisma.disconnect() - }) + await prisma.disconnect(); + }); ``` ## `connect` -The `connect` method establishes a physical connection to the database via Prisma's [query engine](). +The `connect` method establishes a physical connection to the database via Prisma's [query engine](). Note that `connect` returns a `Promise`, so you shsould call it inside an `async` function with the `await` keyword. @@ -48,7 +48,7 @@ Note that `connect` returns a `Promise`, so you should call it inside an `async` ## Connection pool -Once `connect` was called, the query engine immediately creates a connection pool with the amount of connections that were specified as the `connection_limit` parameter on your database connection URL. +Once `connect` was called, the query engine immediately creates a connection pool with the amount of connections that were specified as the `connection_limit` parameter on your database connection URL. For example, with the following `datasource` configuration in your [Prisma schema]() the connection pool will have exactly five connections: diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx index 89ab96e202..2d1c2a7247 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx @@ -34,9 +34,9 @@ The Prisma Client code that's generated from this schema contains this represent ```ts export declare type User = { - id: string; - email: string; - name: string | null; + id: string; + email: string; + name: string | null; }; ``` @@ -52,41 +52,41 @@ As a solution, you can customize the generated model type using Prisma Client's The `User` type only contains the model's [scalar]() fields, but doesn't account for any relations. That's because [relations are not included by default]() in Prisma Client' API calls. -However, sometimes it's useful to have a type available that **includes a relation** (i.e. a type that you'd get from an API call that uses [`include`]()). Similarly, another useful scenario could be to have a type available that **includes only a subset of the model's scalar fields** (i.e. a type that you'd get from an API call that uses [`select`](). +However, sometimes it's useful to have a type available that **includes a relation** (i.e. a type that you'd get from an API call that uses [`include`]()). Similarly, another useful scenario could be to have a type available that **includes only a subset of the model's scalar fields** (i.e. a type that you'd get from an API call that uses [`select`](). One way of achieving this would be to define these types manually in your application code: ```ts -// Define a type that includes the relation to `Post` +// Define a type that includes the relation to `Post` type UserWithPosts = { id: string; email: string; name: string | null; - posts: Post[] -} + posts: Post[]; +}; // Define a type that only contains a subset of the scalar fields type UserPersonalData = { email: string; name: string | null; -} +}; ``` -While this is certainly feasible, this approach increases the maintenance burden upon changes to the Prisma schema as you need to manually maintain the types. A cleaner solution to this is to use the `UserGetIncludePayload` and `UserGetSelectPayload` types that are generated and exposed by Prisma Client: +While this is certainly feasible, this approach increases the maintenance burden upon changes to the Prisma schema as you need to manually maintain the types. A cleaner solution to this is to use the `UserGetIncludePayload` and `UserGetSelectPayload` types that are generated and exposed by Prisma Client: ```ts -import { UserGetIncludePayload, UserGetSelectPayload } from '@prisma/client' +import { UserGetIncludePayload, UserGetSelectPayload } from "@prisma/client"; -// Define a type that includes the relation to `Post` +// Define a type that includes the relation to `Post` type UserWithPosts = UserGetIncludePayload<{ - posts: true -}> + posts: true; +}>; // Define a type that only contains a subset of the scalar fields type UserPersonalData = UserGetSelectPayload<{ email: true; name: true; -}> +}>; ``` The main benefits of the latter approach are: @@ -94,7 +94,7 @@ The main benefits of the latter approach are: - Cleaner approach as it leverages Prisma Client's generated types - Reduced maintenance burden and improved type safety when the schema changes -### Problem: Getting access to the return type of a function +### Problem: Getting access to the return type of a function #### Description @@ -103,8 +103,8 @@ When doing [`select`]() or [`include`]() operations on your models and returning ```ts // Function definition that returns a partial structure async function getUsersWithPosts() { - const users = await prisma.user.findMany({ include: { posts: true } }) - return users + const users = await prisma.user.findMany({ include: { posts: true } }); + return users; } ``` @@ -113,16 +113,16 @@ Extracting the type that represents "users with posts" from the above code snipp ```ts // Function definition that returns a partial structure async function getUsersWithPosts() { - const users = await prisma.user.findMany({ include: { posts: true } }) - return users + const users = await prisma.user.findMany({ include: { posts: true } }); + return users; } -// Extract `UsersWithPosts` type with +// Extract `UsersWithPosts` type with type ThenArg = T extends PromiseLike ? U : T; type UsersWithPosts = ThenArg>; // run inside `async` function -const usersWithPosts: UsersWithPosts = await getUsersWithPosts() +const usersWithPosts: UsersWithPosts = await getUsersWithPosts(); ``` #### Solution @@ -130,7 +130,7 @@ const usersWithPosts: UsersWithPosts = await getUsersWithPosts() With the `PromiseReturnType` that is exposed by Prisma Client, you can solve this more elegantly: ```ts -import { PromiseReturnType } from '@prisma/client' +import { PromiseReturnType } from "@prisma/client"; type UsersWithPosts = PromiseReturnType; -``` \ No newline at end of file +``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx index 7e87d21456..0986b87565 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx @@ -4,4 +4,4 @@ metaTitle: "" metaDescription: "" --- -Coming 🔜 \ No newline at end of file +Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx index ae8a5cac23..a166e1e8e7 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx @@ -4,4 +4,4 @@ metaTitle: "" metaDescription: "" --- -Coming 🔜 \ No newline at end of file +Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx index 8e42391ca2..a38750d215 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx @@ -4,4 +4,4 @@ metaTitle: "" metaDescription: "" --- -Coming 🔜 \ No newline at end of file +Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx index 6b18e36988..187e7734f6 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx @@ -25,7 +25,7 @@ In order to configure these different error formatting levels, there are two opt ## Formatting via environment variables -- `NO_COLOR`: If this env var is provided, colors are stripped from the error message. Therefore you end up with a **colorless error**. The `NO_COLOR` environment variable is a standard described [here](https://no-color.org/). +- `NO_COLOR`: If this env var is provided, colors are stripped from the error message. Therefore you end up with a **colorless error**. The `NO_COLOR` environment variable is a standard described [here](https://no-color.org/). - `NODE_ENV=production`: If the env var `NODE_ENV` is set to `production`, only the **minimal error** will be printed. This allows for easier digestion of logs in production environments. ### Formatting via the `PrismaClient` constructor @@ -41,12 +41,12 @@ It can be used like so: ```ts const prisma = new PrismaClient({ - errorFormat: 'minimal', -}) + errorFormat: "minimal", +}); ``` As the `errorFormat` property is optional, you still can just instantiate Prisma Client like this: ```ts -const prisma = new PrismaClient() -``` \ No newline at end of file +const prisma = new PrismaClient(); +``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx index d3a64e8f0a..210570c5fe 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx @@ -6,7 +6,7 @@ metaDescription: "" ## Overview -A _database transaction_ refers to a sequence of read/write operations that are _guaranteed_ to either succeed or fail as a whole. +A _database transaction_ refers to a sequence of read/write operations that are _guaranteed_ to either succeed or fail as a whole. Transactions are a great tool since they allow developers to disregard a number of potential concurrency problems that can occur when a database processes multiple operations in a short amount of time. Developers take advantage of the _safety guarantees_ provided by the database by wrapping the operations in a transaction. @@ -17,13 +17,13 @@ These guarantees are often summarized using the ACID acronym: - **Isolated**: Ensures that concurrently running transactions have the same effect as if they were running in serial. - **Durability**: Ensures that after the transaction succeeded, any writes are being stored persistently. -While there's a lot of of ambiguity and nuance to each of these properties (e.g. consistency could actually be considered an _application-level responsibility_ rather than a database property or isolation is typically guaranteed in terms of stronger and weaker _isolation levels_), overall they serve as a good high-level guideline for expectations developers have when thinking about database transactions. +While there's a lot of of ambiguity and nuance to each of these properties (e.g. consistency could actually be considered an _application-level responsibility_ rather than a database property or isolation is typically guaranteed in terms of stronger and weaker _isolation levels_), overall they serve as a good high-level guideline for expectations developers have when thinking about database transactions. -> "Transactions are an abstraction layer that allows an application to pretend that certain concurrency problems and certain kinds of hardware and software faults don’t exist. A large class of errors is reduced down to a simple transaction abort, and the application just needs to try again." **[Designing Data-Intensive Applications](https://dataintensive.net/), [Martin Kleppmann](https://twitter.com/martinkl)** +> "Transactions are an abstraction layer that allows an application to pretend that certain concurrency problems and certain kinds of hardware and software faults don’t exist. A large class of errors is reduced down to a simple transaction abort, and the application just needs to try again." **[Designing Data-Intensive Applications](https://dataintensive.net/), [Martin Kleppmann](https://twitter.com/martinkl)** ## How Prisma Client supports transactions today -Prisma Client provides a data access API to read and write data from a database. For relational databases, Prisma Client's API abstracts over SQL where transactions are a common feature. +Prisma Client provides a data access API to read and write data from a database. For relational databases, Prisma Client's API abstracts over SQL where transactions are a common feature. While Prisma Client doesn't allow for the same flexibility a SQL-level transaction provides, it covers the vast majority of use cases developers have for transactions with [**nested writes**](). @@ -32,19 +32,19 @@ A nested write lets you perform a single Prisma Client API call with multiple _o Here are examples for nested writes in the Prisma Client API: ```ts -// Create a new user with two posts in a +// Create a new user with two posts in a // single transaction const newUser: User = await prisma.user.create({ data: { - email: 'alice@prisma.io', + email: "alice@prisma.io", posts: { create: [ - { title: 'Join the Prisma Slack on https://slack.prisma.io' }, - { title: 'Follow @prisma on Twitter' }, + { title: "Join the Prisma Slack on https://slack.prisma.io" }, + { title: "Follow @prisma on Twitter" }, ], }, }, -}) +}); ``` ```ts @@ -53,10 +53,10 @@ const updatedPost: Post = await prisma.post.update({ where: { id: 42 }, data: { author: { - connect: { email: 'alice@prisma.io' }, + connect: { email: "alice@prisma.io" }, }, }, -}) +}); ``` ## Future transaction support in Prisma Client @@ -66,17 +66,16 @@ Transactions are a commonly used feature in relational as well as non-relational - Sending multiple operations in bulk - Enabling longer-running transactions where operations can depend on each other - ### Bulk operations The first use case of sending multiple operations in bulk could be implemented with an API similar to this: ```ts -const write1 = prisma.user.create() -const write2 = prisma.orders.create() -const write3 = prisma.invoices.create() +const write1 = prisma.user.create(); +const write2 = prisma.orders.create(); +const write3 = prisma.invoices.create(); -await prisma.transaction([write1, write2, write3]) +await prisma.transaction([write1, write2, write3]); ``` Instead of immediately awaiting the result of each operation when it's performed, the operation itself is stored in a variable first which later is submitted to the database via a method called `transaction`. Prisma Client will ensure that either all three `create`-operations or none of them succeed. @@ -88,21 +87,21 @@ The second use case of longer-running transactions where operations can depend o ```ts prisma.transaction(async tx => { const user = await tx.users.create({ - data: { email: "alice@prisma.io" } - }) + data: { email: "alice@prisma.io" }, + }); const order = await tx.orders.create({ data: { customer: { - connect: { id: user.id } - } - } - }) - await tx.commit() -}) + connect: { id: user.id }, + }, + }, + }); + await tx.commit(); +}); ``` In this case, the API provides a way to wrap a sequence of operations in a callback which gets executed as a transaction, therefore is guaranteed to either succeed or fail as a whole. ### Join the conversation on GitHub -If you'd like to see transactions supported in the future, [please join the discussion on GitHub](https://github.com/prisma/prisma-client-js/issues/349). \ No newline at end of file +If you'd like to see transactions supported in the future, [please join the discussion on GitHub](https://github.com/prisma/prisma-client-js/issues/349). diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx index 7d18c524ba..ead6beeb22 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx @@ -18,13 +18,12 @@ This page covers relevant technical details about the query engine. ### The query engine binary file -The **query engine binary file** is called `query-engine-PLATFORM` where `PLATFORM` corresponds to the name of a compile target. For example, if the query engine must run on a [Darwin](https://en.wikipedia.org/wiki/Darwin_(operating_system)) operating system (e.g. Mac OS), it's called `query-engine-darwin`. You can find an overview of all supported platforms [here](). +The **query engine binary file** is called `query-engine-PLATFORM` where `PLATFORM` corresponds to the name of a compile target. For example, if the query engine must run on a [Darwin]() operating system (e.g. Mac OS), it's called `query-engine-darwin`. You can find an overview of all supported platforms [here](). The query engine binary file is downloaded into the `runtime` directory of `node_modules/@prisma/client` when `prisma generate` is called. Note that the query engine is implemented in Rust. The source code is located in the [`prisma-engines`](https://github.com/prisma/prisma-engines/) repository. - ## The query engine at runtime The query engine is running as a separate process on the same machine where the Node.js/TypeScript application is running. @@ -33,7 +32,7 @@ The query engine is running as a separate process on the same machine where the The query engine process is started when the [`connect()`]() method is called on your `PrismaClient` instance. Once the process is started, the query engine creates a [connnection pool]() and manages the physical connections to the database. From that point onwards, Prisma Client is ready to send [queries]() to the database (e.g. `findOne`, `findMany`, `create`, ...). -The query engine process is stopped and the database connections are closed when [`disconnect()`]() is invoked. +The query engine process is stopped and the database connections are closed when [`disconnect()`]() is invoked. The following diagram depicts a "typical flow": @@ -73,8 +72,8 @@ You can also get more visibility into the SQL queries that are generated by the ```ts const prisma = new PrismaClient({ - log: ['query'] -}) + log: ["query"], +}); ``` -Learn more in the [debugging]() and [logging]() sections of the docs. \ No newline at end of file +Learn more in the [debugging]() and [logging]() sections of the docs. diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx index a89bc818fe..1f67de3355 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx @@ -1,7 +1,7 @@ --- - title: "Prisma Client API" - metaTitle: "" - metaDescription: "" +title: "Prisma Client API" +metaTitle: "" +metaDescription: "" --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx index c25195ce2d..7ca9819493 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx @@ -1,6 +1,5 @@ --- - title: "Prisma Client" - metaTitle: "" - metaDescription: "" +title: "Prisma Client" +metaTitle: "" +metaDescription: "" --- - diff --git a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx index 3f7aa439eb..2ba2096d40 100644 --- a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx @@ -1,7 +1,6 @@ --- - title: "Prisma Migrate" - metaTitle: "" - metaDescription: "" - experimental: true +title: "Prisma Migrate" +metaTitle: "" +metaDescription: "" +experimental: true --- - diff --git a/content/03-reference/01-tools-and-interfaces/04-introspection.mdx b/content/03-reference/01-tools-and-interfaces/04-introspection.mdx index ef4759859a..88391c6786 100644 --- a/content/03-reference/01-tools-and-interfaces/04-introspection.mdx +++ b/content/03-reference/01-tools-and-interfaces/04-introspection.mdx @@ -1,7 +1,7 @@ --- - title: "Introspection" - metaTitle: "" - metaDescription: "" +title: "Introspection" +metaTitle: "" +metaDescription: "" --- -Coming 🔜 \ No newline at end of file +Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx index 6d180408c0..3161a91dff 100644 --- a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx +++ b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx @@ -54,7 +54,7 @@ yarn prisma2 generate ## Global installation -While it is recommended to [locally install](#local-installation-recommended) the `prisma2` CLI, you can also install it globally on your machine. +While it is recommended to [locally install](#local-installation-recommended) the `prisma2` CLI, you can also install it globally on your machine. > **Warning**: If you have several Prisma projects on your machine, a global installation can lead to version conflicts between these projects. @@ -78,7 +78,6 @@ Here's an example for invoking the `generate` command: prisma2 generate ``` - #### Yarn Install with Yarn: @@ -97,4 +96,4 @@ Here's an example for invoking the `generate` command: ``` prisma2 generate -``` \ No newline at end of file +``` diff --git a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx index 0a8130fa9c..9a9043b19d 100644 --- a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx +++ b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx @@ -6,7 +6,7 @@ metaDescription: "" ## Overview -The Prisma command line interface (CLI) is the primary way to interact with your Prisma project from the command line. It can initialize new project assets, generate Prisma Client, and analyze existing database structures through introspection to automatically create your application models. +The Prisma command line interface (CLI) is the primary way to interact with your Prisma project from the command line. It can initialize new project assets, generate Prisma Client, and analyze existing database structures through introspection to automatically create your application models. Along with these features, there are also a few experimental commands that you you can access if you'd like to use in-progress functionality (e.g. Prisma Migrate or Prisma Studio). @@ -14,11 +14,12 @@ This document will explain the Prisma CLI's commands, arguments, and options. ## Synopsis -The `prisma2` command can be called from command line once installed. When called without arguments, it will display its command usage and help document: +The `prisma2` command can be called from command line once installed. When called without arguments, it will display its command usage and help document: ```shell prisma2 ``` + ``` ◭ Prisma is a modern DB toolkit to query, migrate and model your database (https://prisma.io) @@ -56,7 +57,7 @@ You can get additional help on any of the `prisma2` commands by adding the `--he Bootstraps a fresh Prisma project within the current directory. -The `init` command does not interpret any existing files. Instead, it creates a `prisma` directory containing a bare-bones `schema.prisma` file within your current directory. +The `init` command does not interpret any existing files. Instead, it creates a `prisma` directory containing a bare-bones `schema.prisma` file within your current directory. #### Examples @@ -65,6 +66,7 @@ The `init` command does not interpret any existing files. Instead, it creates a ```shell prisma2 init ``` + ``` ✔ Your Prisma schema was created at prisma/schema.prisma. You can now open it in your favorite editor. @@ -119,15 +121,15 @@ DATABASE_URL="postgresql://johndoe:johndoe@localhost:5432/mydb?schema=public" The `generate` command generates assets like Prisma Client based on the [`generator`](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md#generators-optional) and [`model`](https://github.com/prisma/prisma2/blob/master/docs/data-modeling.md) blocks defined in your `prisma/schema.prisma` file. -The `generate` command is most often used to generate Prisma Client with the `prisma-client-js` generator. This does three things: +The `generate` command is most often used to generate Prisma Client with the `prisma-client-js` generator. This does three things: -1. Searches the current directory and parent directories to find the applicable `npm` project. It will create a `package.json` file in the current directory if it cannot find one. +1. Searches the current directory and parent directories to find the applicable `npm` project. It will create a `package.json` file in the current directory if it cannot find one. 2. Installs the `@prisma/client` into the `npm` project if it is not already present. -3. Inspects the current directory to find a Prisma schema file to process. It will then generate a customized [Prisma Client](https://github.com/prisma/prisma-client-js) for your project. +3. Inspects the current directory to find a Prisma schema file to process. It will then generate a customized [Prisma Client](https://github.com/prisma/prisma-client-js) for your project. #### Prerequisites -To use the `generate` command, you must add a generator definition in your `schema.prisma` file. The `prisma-client-js` generator, used to generate Prisma Client, can be added by including the following in your `schema.prisma` file: +To use the `generate` command, you must add a generator definition in your `schema.prisma` file. The `prisma-client-js` generator, used to generate Prisma Client, can be added by including the following in your `schema.prisma` file: ```prisma generator client { @@ -139,10 +141,10 @@ generator client { The `generate` command recognizes the following options to modify its behavior: -| Option | Required | Description | Default | -| ------ | -------- | ----------- | ------- | -| `--schema` | No | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`, `./prisma/schema.prisma` | -| `--watch` | No | The `generate` command will continue to watch the `schema.prisma` file and re-generate Prisma Client on file changes. | +| Option | Required | Description | Default | +| ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | +| `--schema` | No | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`, `./prisma/schema.prisma` | +| `--watch` | No | The `generate` command will continue to watch the `schema.prisma` file and re-generate Prisma Client on file changes. | #### Examples @@ -176,6 +178,7 @@ prisma2 generate --schema=./alternative/schema.prisma ```shell prisma2 generate --watch ``` + ``` Watching... /home/prismauser/prisma/prisma-play/prisma/schema.prisma @@ -192,7 +195,7 @@ The `introspect` command connects to your database and adds Prisma models to you To run the `introspect` command, a `schema.prisma` file with a valid [`datasource`](https://github.com/prisma/prisma2/blob/master/docs/prisma-schema-file.md#data-sources) must be available. -> Warning: The command will overwrite the current `schema.prisma` file with the new schema. Any manual changes or customization will be lost. Be sure to back up your current `schema.prisma` file before running `introspect` if it contains important modifications. +> Warning: The command will overwrite the current `schema.prisma` file with the new schema. Any manual changes or customization will be lost. Be sure to back up your current `schema.prisma` file before running `introspect` if it contains important modifications. #### Prerequisites @@ -211,10 +214,10 @@ datasource db { The `introspect` command recognizes the following options to modify its behavior: -| Option | Required | Description | Default | -| ------ | -------- | ----------- | ------- | -| `--schema` | No | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`, `./prisma/schema.prisma` | -| `--print` | No | Prints the created `schema.prisma` to the screen instead of writing it to the filesystem. | +| Option | Required | Description | Default | +| ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | +| `--schema` | No | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`, `./prisma/schema.prisma` | +| `--print` | No | Prints the created `schema.prisma` to the screen instead of writing it to the filesystem. | #### Examples @@ -223,6 +226,7 @@ The `introspect` command recognizes the following options to modify its behavior ```shell prisma2 introspect ``` + ``` Introspecting based on datasource defined in schema.prisma … @@ -236,6 +240,7 @@ Run prisma2 generate to generate Prisma Client. ```shell prisma2 introspect --schema=./alternative/schema.prisma ``` + ``` Introspecting based on datasource defined in alternative/schema.prisma … @@ -249,6 +254,7 @@ Run prisma2 generate to generate Prisma Client. ```shell prisma2 introspect --print ``` + ```prisma generator client { provider = "prisma-client-js" @@ -283,9 +289,9 @@ model Profile { ## Migrations (Experimental) -> Warning: The `migrate` command is still considered experimental. As such, there are no guarantees about API stability or production-readiness. Access to this command is provided for evaluation and experimentation. To access experimental commands, you must add the `--experimental` flag. +> Warning: The `migrate` command is still considered experimental. As such, there are no guarantees about API stability or production-readiness. Access to this command is provided for evaluation and experimentation. To access experimental commands, you must add the `--experimental` flag. -The `migrate` command creates and manages database migrations. It can be used to create, apply, and rollback database schema updates in a controlled manner. +The `migrate` command creates and manages database migrations. It can be used to create, apply, and rollback database schema updates in a controlled manner. The `migrate` command includes a number of subcommands to specify the desired action. @@ -310,23 +316,23 @@ datasource db { The `migrate save` command recognizes the following options to modify its behavior: -| Option | Required | Description | -| ------ | -------- | ----------- | -| `--experimental` | Yes | Enables use of experimental commands. | -| `-n`, `--name` | No | The name of the migration. If not provided, `migrate save` will prompt you for a name. | -| `-c`, `--create-db` | No | Create the database if it does not exist. | -| `-p`, `--preview` | No | Preview the migration that would be created without writing any changes to the filesystem. | +| Option | Required | Description | +| ------------------- | -------- | ------------------------------------------------------------------------------------------ | +| `--experimental` | Yes | Enables use of experimental commands. | +| `-n`, `--name` | No | The name of the migration. If not provided, `migrate save` will prompt you for a name. | +| `-c`, `--create-db` | No | Create the database if it does not exist. | +| `-p`, `--preview` | No | Preview the migration that would be created without writing any changes to the filesystem. | #### Generated Assets The `migrate save` command generates the following directories and files as necessary: -* `migrations`: A directory within the current project to store migrations. This directory will be created if it does not exist. -* `migrations/migrate.lock`: A lock file created specifying the current migration applied to the database. This file will be created if it does not exist. -* `migrations/`: A directory for a specific migration. The migration name is derived from the timestamp when it was created followed by a hyphen and the migration name provided by the user. -* `migrations//README.md`: A human-readable description of the migration including metadata like when the migration was created and by who, a list of the actual migration changes and a diff of the changes that are made to the `schema.prisma` file. -* `migrations//schema.prisma`: The schema that will be created if the migration is applied to the project. -* `migrations//steps.json`: An [alternative representation](https://github.com/prisma/specs/tree/master/lift#step) of the migration steps that will be applied. +- `migrations`: A directory within the current project to store migrations. This directory will be created if it does not exist. +- `migrations/migrate.lock`: A lock file created specifying the current migration applied to the database. This file will be created if it does not exist. +- `migrations/`: A directory for a specific migration. The migration name is derived from the timestamp when it was created followed by a hyphen and the migration name provided by the user. +- `migrations//README.md`: A human-readable description of the migration including metadata like when the migration was created and by who, a list of the actual migration changes and a diff of the changes that are made to the `schema.prisma` file. +- `migrations//schema.prisma`: The schema that will be created if the migration is applied to the project. +- `migrations//steps.json`: An [alternative representation](https://github.com/prisma/specs/tree/master/lift#step) of the migration steps that will be applied. #### Examples @@ -336,7 +342,7 @@ The `migrate save` command generates the following directories and files as nece prism2 migrate save --experimental ``` -The command will prompt you for a name for the migration since one was not provided on the command line. After creating the migration, the contents of the generated `schema.prisma` file are displayed. +The command will prompt you for a name for the migration since one was not provided on the command line. After creating the migration, the contents of the generated `schema.prisma` file are displayed. **Create a migration with a specific name** @@ -377,21 +383,21 @@ datasource db { The point to migrate the database up to can be defined in any of the following three ways: -| Argument | Required | Description | Default | -| -------- | -------- | ---------- | -------- | -| increment | No | Specifies the number of forward migrations to apply. | latest | -| name | No | Specifies where to migrate to using the name of the final migration to apply. | latest | -| timestamp | No | Specifies where to migrate to using the timestamp of the final migration to apply. | latest | +| Argument | Required | Description | Default | +| --------- | -------- | ---------------------------------------------------------------------------------- | ------- | +| increment | No | Specifies the number of forward migrations to apply. | latest | +| name | No | Specifies where to migrate to using the name of the final migration to apply. | latest | +| timestamp | No | Specifies where to migrate to using the timestamp of the final migration to apply. | latest | #### Options Additionally, the following options modify the behavior of the `migrate up` command: -| Option | Required | Description | -| ------ | -------- | ----------- | -| `--experimental` | Yes | Enables use of experimental commands | -| `-c`, `--create-db` | No | Create the database if it does not exist. | -| `-p`, `--preview` | No | Preview the migration that would be created without writing any changes to the filesystem. | +| Option | Required | Description | +| ------------------- | -------- | ------------------------------------------------------------------------------------------ | +| `--experimental` | Yes | Enables use of experimental commands | +| `-c`, `--create-db` | No | Create the database if it does not exist. | +| `-p`, `--preview` | No | Preview the migration that would be created without writing any changes to the filesystem. | #### Examples @@ -452,20 +458,20 @@ datasource db { The point to migrate back to can be defined in any of the following three ways: -| Argument | Required | Description | Default | -| -------- | -------- | ----------- | ------- | -| decrement | No | Specifies the number of backwards migrations to apply. | 1 | -| name | No | Specifies where to migrate back to using the name of the final migration to apply. | -| timestamp | No | Specifies where to migrate back to using the timestamp of the final migration to apply. | +| Argument | Required | Description | Default | +| --------- | -------- | --------------------------------------------------------------------------------------- | ------- | +| decrement | No | Specifies the number of backwards migrations to apply. | 1 | +| name | No | Specifies where to migrate back to using the name of the final migration to apply. | +| timestamp | No | Specifies where to migrate back to using the timestamp of the final migration to apply. | #### Options Additionally, the following options modify the behavior of the `migrate down` command: -| Option | Required | Description | -| ------ | -------- | ----------- | -| `--experimental` | Yes | Enables use of experimental commands | -| `-p`, `--preview` | No | Preview the migration that would be created without writing any changes to the filesystem. | +| Option | Required | Description | +| ----------------- | -------- | ------------------------------------------------------------------------------------------ | +| `--experimental` | Yes | Enables use of experimental commands | +| `-p`, `--preview` | No | Preview the migration that would be created without writing any changes to the filesystem. | #### Examples @@ -480,6 +486,7 @@ prisma2 migrate down --experimental ```shell prisma2 migrate down 2 --experimental ``` + **Migrate backwards through all migrations up to and including a migration by name** ```shell @@ -502,9 +509,9 @@ prisma2 migrate down --preview --experimental ### studio -> Warning: The `studio` command is still considered experimental. As such, there are no guarantees about API stability or production-readiness. Access to this command is provided for evaluation and experimentation. To access experimental commands, you must add the `--experimental` flag. +> Warning: The `studio` command is still considered experimental. As such, there are no guarantees about API stability or production-readiness. Access to this command is provided for evaluation and experimentation. To access experimental commands, you must add the `--experimental` flag. -The `studio` command allows you to interact with and manage your data interactively. It does this by starting a local web server with a web app configured with your project's data schema and records. +The `studio` command allows you to interact with and manage your data interactively. It does this by starting a local web server with a web app configured with your project's data schema and records. #### Prerequisites @@ -523,10 +530,10 @@ datasource db { The `studio` command recognizes the following options: -| Option | Required | Description | Default | -| ------ | -------- | ----------- | -------- | -| `--experimental` | Yes | Enables use of experimental commands | -| `-p`, `--port` | No | The port number to start Studio on. | 5555 | +| Option | Required | Description | Default | +| ---------------- | -------- | ------------------------------------ | ------- | +| `--experimental` | Yes | Enables use of experimental commands | +| `-p`, `--port` | No | The port number to start Studio on. | 5555 | #### Examples diff --git a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx index 4b7274431c..ed81f6243a 100644 --- a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx @@ -1,5 +1,5 @@ --- - title: "Prisma CLI" - metaTitle: "" - metaDescription: "" ---- \ No newline at end of file +title: "Prisma CLI" +metaTitle: "" +metaDescription: "" +--- diff --git a/content/03-reference/01-tools-and-interfaces/index.mdx b/content/03-reference/01-tools-and-interfaces/index.mdx index 7193cf2f63..02ed00f97c 100644 --- a/content/03-reference/01-tools-and-interfaces/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/index.mdx @@ -1,6 +1,6 @@ --- - title: "Tools & Interfaces" - metaTitle: "" - metaDescription: "" - staticLink: true ---- \ No newline at end of file +title: "Tools & Interfaces" +metaTitle: "" +metaDescription: "" +staticLink: true +--- diff --git a/content/03-reference/02-database-connectors/01-postgresql.mdx b/content/03-reference/02-database-connectors/01-postgresql.mdx index 2f6848b75c..ddd5726d7d 100644 --- a/content/03-reference/02-database-connectors/01-postgresql.mdx +++ b/content/03-reference/02-database-connectors/01-postgresql.mdx @@ -4,4 +4,4 @@ metaTitle: "" metaDescription: "" --- -Coming 🔜 \ No newline at end of file +Coming 🔜 diff --git a/content/03-reference/02-database-connectors/02-mysql.mdx b/content/03-reference/02-database-connectors/02-mysql.mdx index e91beeb501..67d54a5daf 100644 --- a/content/03-reference/02-database-connectors/02-mysql.mdx +++ b/content/03-reference/02-database-connectors/02-mysql.mdx @@ -4,4 +4,4 @@ metaTitle: "" metaDescription: "" --- -Coming 🔜 \ No newline at end of file +Coming 🔜 diff --git a/content/03-reference/02-database-connectors/03-sqlite.mdx b/content/03-reference/02-database-connectors/03-sqlite.mdx index 5fe962e291..6c5df7a9ed 100644 --- a/content/03-reference/02-database-connectors/03-sqlite.mdx +++ b/content/03-reference/02-database-connectors/03-sqlite.mdx @@ -4,4 +4,4 @@ metaTitle: "" metaDescription: "" --- -Coming 🔜 \ No newline at end of file +Coming 🔜 diff --git a/content/03-reference/02-database-connectors/index.mdx b/content/03-reference/02-database-connectors/index.mdx index f938528c0a..7f5f15f393 100644 --- a/content/03-reference/02-database-connectors/index.mdx +++ b/content/03-reference/02-database-connectors/index.mdx @@ -1,6 +1,6 @@ --- - title: "Database connectors" - metaTitle: "" - metaDescription: "" - staticLink: true ---- \ No newline at end of file +title: "Database connectors" +metaTitle: "" +metaDescription: "" +staticLink: true +--- diff --git a/content/03-reference/03-more/01-editor-setup.mdx b/content/03-reference/03-more/01-editor-setup.mdx index 1aece765bb..d4abe277fd 100644 --- a/content/03-reference/03-more/01-editor-setup.mdx +++ b/content/03-reference/03-more/01-editor-setup.mdx @@ -4,4 +4,4 @@ metaTitle: "" metaDescription: "" --- -Coming 🔜 \ No newline at end of file +Coming 🔜 diff --git a/content/03-reference/03-more/02-telemetry.mdx b/content/03-reference/03-more/02-telemetry.mdx index cd5726df0a..ac69c2d4cd 100644 --- a/content/03-reference/03-more/02-telemetry.mdx +++ b/content/03-reference/03-more/02-telemetry.mdx @@ -68,4 +68,4 @@ export CHECKPOINT_DISABLE=1 ### Error reporting -You can opt-out of data collection by responding to the interactive prompt with _no_. \ No newline at end of file +You can opt-out of data collection by responding to the interactive prompt with _no_. diff --git a/content/03-reference/03-more/index.mdx b/content/03-reference/03-more/index.mdx index 687633041c..c63f53691e 100644 --- a/content/03-reference/03-more/index.mdx +++ b/content/03-reference/03-more/index.mdx @@ -1,6 +1,6 @@ --- - title: "More" - metaTitle: "" - metaDescription: "" - staticLink: true ---- \ No newline at end of file +title: "More" +metaTitle: "" +metaDescription: "" +staticLink: true +--- diff --git a/content/03-reference/index.mdx b/content/03-reference/index.mdx index 8695da8a87..c4c60d2c77 100644 --- a/content/03-reference/index.mdx +++ b/content/03-reference/index.mdx @@ -1,5 +1,5 @@ --- - title: "Reference" - metaTitle: "Reference" - metaDescription: "Reference" ---- \ No newline at end of file +title: "Reference" +metaTitle: "Reference" +metaDescription: "Reference" +--- diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx index 5f69d12d6d..cd0bf063cf 100644 --- a/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx @@ -5,4 +5,3 @@ metaDescription: "" --- Coming 🔜 - diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx index 8f4dd93992..a5f54160cf 100644 --- a/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx @@ -5,6 +5,3 @@ metaDescription: "" --- Coming 🔜 - - - diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx index 4e80115a96..aef141b55c 100644 --- a/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx @@ -1,4 +1,4 @@ --- title: "Setting up a database" metaTitle: "" ---- \ No newline at end of file +--- diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx index d21fb2dea0..c2e4c62161 100644 --- a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx @@ -12,9 +12,9 @@ This document describes how you can export data from and import data into a Post [SQL Dump](https://www.postgresql.org/docs/9.1/backup-dump.html) is a native PostgreSQL utility you can use to export data from your PostgreSQL database. To see all the options for this command, run `pg_dump --help`. -From the PostgreSQL docs: +From the PostgreSQL docs: -> The idea behind this dump method is to generate a text file with SQL commands that, when fed back to the server, will recreate the database in the same state as it was at the time of the dump. PostgreSQL provides the utility program `pg_dump` for this purpose. +> The idea behind this dump method is to generate a text file with SQL commands that, when fed back to the server, will recreate the database in the same state as it was at the time of the dump. PostgreSQL provides the utility program `pg_dump` for this purpose. > `pg_dump` is a regular PostgreSQL client application (albeit a particularly clever one). This means that you can perform this backup procedure from any remote host that has access to the database. But remember that pg_dump does not operate with special permissions. In particular, it must have read access to all tables that you want to back up, so in practice you almost always have to run it as a database superuser. The command looks like this: @@ -23,7 +23,7 @@ The command looks like this: pg_dump DB_NAME > OUTPUT_FILE ``` -You need to replace the `DB_NAME` and `OUTPUT_FILE` placeholders with the respective values for: +You need to replace the `DB_NAME` and `OUTPUT_FILE` placeholders with the respective values for: - your **database name** - the name of the desired **output file** (should end on `.sql`) @@ -40,15 +40,16 @@ If your database schema uses [Object Idenfitifier Types](https://www.postgresql. You can add the following arguments to specify the location of your PostgreSQL database server: -| Argument | Default | Env var | Description | -| --- | --- | --- | --- | -| `--host` (short: `-h`) | `localhost` | `PGHOST` | The address of the server's host machine | -| `--port` (short: `-p`) | - | `PGPORT` | The port of the server's host machine where the PostgreSQL server is listening | +| Argument | Default | Env var | Description | +| ---------------------- | ----------- | -------- | ------------------------------------------------------------------------------ | +| `--host` (short: `-h`) | `localhost` | `PGHOST` | The address of the server's host machine | +| `--port` (short: `-p`) | - | `PGPORT` | The port of the server's host machine where the PostgreSQL server is listening | + To authenticate against the PostgreSQL database server, you can use the following argument: -| Argument | Default | Env var | Description | -| --- | --- | --- | --- | -| `--username` (short: `-U`) | _your current operating system user name_ | `PGUSER` | The name of the database user. | +| Argument | Default | Env var | Description | +| -------------------------- | ----------------------------------------- | -------- | ------------------------------ | +| `--username` (short: `-U`) | _your current operating system user name_ | `PGUSER` | The name of the database user. | For example, if you want to export data from a PostgerSQL database that has the following [connection string](../core/connectors/postgresql.md): @@ -76,14 +77,14 @@ There might be cases where you don't want to dump the _entire_ database, for exa Here's an overview of a few command line options you can use in these scenarios: -| Argument | Default | Description | -| --- | --- | --- | -| `--data-only` (short: `-a`) | `false` | Exclude any [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements and export only data. | -| `--schema-only` (short: `-s`) | `false` | Exclude data and export only [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements. | -| `--blobs` (short: `-b`) | `true` unless either `-schema`, `--table`, or `--schema-only` options are specified | Include binary large objects. | -| `--no-blobs` (short: `-B`) | `false` | Exclude binary large objects. | -| `--table` (short: `-t`) | _includes all tables by default_ | Explicitly specify the names of the tables to be dumped. | -| `--exclude-table` (short: `-T`) | - | Exclude specific tables from the dump. | +| Argument | Default | Description | +| ------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| `--data-only` (short: `-a`) | `false` | Exclude any [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements and export only data. | +| `--schema-only` (short: `-s`) | `false` | Exclude data and export only [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements. | +| `--blobs` (short: `-b`) | `true` unless either `-schema`, `--table`, or `--schema-only` options are specified | Include binary large objects. | +| `--no-blobs` (short: `-B`) | `false` | Exclude binary large objects. | +| `--table` (short: `-t`) | _includes all tables by default_ | Explicitly specify the names of the tables to be dumped. | +| `--exclude-table` (short: `-T`) | - | Exclude specific tables from the dump. | ## Importing data from SQL files @@ -93,7 +94,7 @@ After having used SQL Dump to export your PostgreSQL database as a SQL file, you psql DB_NAME < INPUT_FILE ``` -You need to replace the `DB_NAME` and `INPUT_FILE` placeholders with the respective values for: +You need to replace the `DB_NAME` and `INPUT_FILE` placeholders with the respective values for: - your **database name** (a database with hat name must be created beforehand!) - the name of the target **input file** (likely ends on `.sql`) @@ -102,4 +103,4 @@ To create the database `DB_NAME` beforehand, you can use the [`template0`](https ```sql CREATE DATABASE dbname TEMPLATE template0; -``` \ No newline at end of file +``` diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx index cb4c9d9be8..e75b3de43f 100644 --- a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx @@ -14,7 +14,7 @@ This document describes how you can export data from and import data into a MySQ Note that your [MySQL installation](https://dev.mysql.com/doc/refman/8.0/en/installing.html) comes with `mysqldump` by default, typically contained in `/usr/local/mysql/bin` on Mac OS. This means you can either invoke the command by pointing to that directory `/usr/local/mysql/bin/mysqldump` or [adding it to your `PATH`](https://stackoverflow.com/questions/30990488/how-do-i-install-command-line-mysql-client-on-mac#answer-35338119) so that you can run `mysqldump` without specifying the directory. -From the MySQL docs: +From the MySQL docs: > The `mysqldump` client utility performs logical backups, producing a set of SQL statements that can be executed to reproduce the original database object definitions and table data. It dumps one or more MySQL databases for backup or transfer to another SQL server. The `mysqldump` command can also generate output in CSV, other delimited text, or XML format. @@ -24,7 +24,7 @@ The command looks like this: mysqldump DB_NAME > OUTPUT_FILE ``` -You need to replace the `DB_NAME` and `OUTPUT_FILE` placeholders with the respective values for: +You need to replace the `DB_NAME` and `OUTPUT_FILE` placeholders with the respective values for: - your **database name** - the name of the desired **output file** (should end on `.sql`) @@ -39,17 +39,17 @@ mysqldump mydb > mydb.sql You can add the following arguments to specify the location of your MySQL database server: -| Argument | Default | Description | -| --- | --- | --- | -| `--host` (short: `-h`) | `localhost` | The address of the server's host machine | -| `--port` (short: `-p`) | - | The port of the server's host machine where the MySQL server is listening | +| Argument | Default | Description | +| ---------------------- | ----------- | ------------------------------------------------------------------------- | +| `--host` (short: `-h`) | `localhost` | The address of the server's host machine | +| `--port` (short: `-p`) | - | The port of the server's host machine where the MySQL server is listening | To authenticate against the MySQL database server, you can use the following argument: -| Argument | Default | Description | -| --- | --- | --- | -| `--user` (short: `-u`) | - | The name of the database user. | -| `--password` (short: `-p`) | - | Trigger password prompt. | +| Argument | Default | Description | +| -------------------------- | ------- | ------------------------------ | +| `--user` (short: `-u`) | - | The name of the database user. | +| `--password` (short: `-p`) | - | Trigger password prompt. | For example, if you want to export data from a MySQL database that has the following [connection string](../core/connectors/mysql.md): @@ -75,12 +75,12 @@ There might be cases where you don't want to dump the _entire_ database, for exa Here's an overview of a few command line options you can use in these scenarios: -| Argument | Default | Description | -| --- | --- | --- | -| `--no-create-db` (short: `-n`) | `false` | Exclude any [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements and export only data. | -| `--no-data` (short: `-d`) | `false` | Exclude data and export only [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements. | -| `--tables`| _includes all tables by default_ | Explicitly specify the names of the tables to be dumped. | -| `--ignore-table` | - | Exclude specific tables from the dump. | +| Argument | Default | Description | +| ------------------------------ | -------------------------------- | ------------------------------------------------------------------------------------------------ | +| `--no-create-db` (short: `-n`) | `false` | Exclude any [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements and export only data. | +| `--no-data` (short: `-d`) | `false` | Exclude data and export only [DDL](https://www.postgresql.org/docs/8.4/ddl.html) statements. | +| `--tables` | _includes all tables by default_ | Explicitly specify the names of the tables to be dumped. | +| `--ignore-table` | - | Exclude specific tables from the dump. | ## Importing data from SQL files @@ -92,7 +92,7 @@ mysql DB_NAME INPUT_FILE Note that your [MySQL installation](https://dev.mysql.com/doc/refman/8.0/en/installing.html) comes with `mysql` by default, typically contained in `/usr/local/mysql/bin` on Mac OS. This means you can either invoke the command by pointing to that directory `/usr/local/mysql/bin/mysmysqlqldump` or [adding it to your `PATH`](https://stackoverflow.com/questions/30990488/how-do-i-install-command-line-mysql-client-on-mac#answer-35338119) so that you can run `mysql` without specifying the directory. -You need to replace the `DB_NAME` and `INPUT_FILE` placeholders with the respective values for: +You need to replace the `DB_NAME` and `INPUT_FILE` placeholders with the respective values for: - your **database name** (a database with hat name must be created beforehand!) - the name of the target **input file** (likely ends on `.sql`) @@ -114,5 +114,3 @@ To create a database beforehand, you can use the following SQL statement: ```sql CREATE DATABASE mydb; ``` - - diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx index 7547dd1f02..3544559761 100644 --- a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx @@ -1,4 +1,4 @@ --- -title: "Importing and exporting data"" +title: "Importing and exporting data" metaTitle: "" ------- \ No newline at end of file +--- diff --git a/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx b/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx index f77fdc9f9b..47afcbc3ed 100644 --- a/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx @@ -5,4 +5,3 @@ metaDescription: "" --- Coming 🔜 - diff --git a/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx b/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx index dda7521ea3..fe00ec33ce 100644 --- a/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx @@ -5,6 +5,3 @@ metaDescription: "" --- Coming 🔜 - - - diff --git a/content/04-guides/01-database-workflows/03-primary-keys/index.mdx b/content/04-guides/01-database-workflows/03-primary-keys/index.mdx index 1eaccdb498..ed56855a19 100644 --- a/content/04-guides/01-database-workflows/03-primary-keys/index.mdx +++ b/content/04-guides/01-database-workflows/03-primary-keys/index.mdx @@ -1,4 +1,4 @@ --- title: "Primary keys" metaTitle: "" ------- \ No newline at end of file +--- diff --git a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx index c2c65464d6..427bc21ada 100644 --- a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx +++ b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx @@ -1,4 +1,4 @@ --- title: "Unique constraints and indexes" metaTitle: "" ------- \ No newline at end of file +--- diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx index a3970e8668..0bd230df68 100644 --- a/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx @@ -190,7 +190,7 @@ model User { To validate whether the foreign key constraints work, you'll now generate Prisma Client and send a few sample queries to the database to test the relations. -First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): ```prisma generator client { @@ -211,9 +211,9 @@ Now you can use Prisma Client to send database queries in Node.js. Create a new file called `index.js` and add the following code to it: ```js -const { PrismaClient } = require('@prisma/client') +const { PrismaClient } = require("@prisma/client"); -const prisma = new PrismaClient() +const prisma = new PrismaClient(); async function main() { const userWithPost = await prisma.user.create({ @@ -221,15 +221,15 @@ async function main() { name: "Alice", post: { create: { - title: "Hello World from Alice" - } - } + title: "Hello World from Alice", + }, + }, }, include: { - post: true - } - }) - console.log(userWithPost) + post: true, + }, + }); + console.log(userWithPost); const anotherUserWithPost = await prisma.anotherUser.create({ data: { @@ -237,18 +237,18 @@ async function main() { lastName: "Smith", anotherPost: { create: { - title: "Hello World from Bob" - } - } + title: "Hello World from Bob", + }, + }, }, include: { - anotherPost: true - } - }) - console.log(anotherUserWithPost) + anotherPost: true, + }, + }); + console.log(anotherUserWithPost); } -main() +main(); ``` In this code, you're creating two `User` records, each with a related `Post` record. diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx index d114bbc945..0891f607e0 100644 --- a/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx +++ b/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx @@ -1,4 +1,4 @@ --- title: "Foreign keys" metaTitle: "" ------- \ No newline at end of file +--- diff --git a/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx b/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx index 72791482fd..1c2708b09a 100644 --- a/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx +++ b/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx @@ -1,4 +1,4 @@ --- title: "Cascading deletes" metaTitle: "" ------- +--- diff --git a/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx b/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx index 171ebfef85..60ee70c43c 100644 --- a/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx @@ -18,7 +18,7 @@ In order to follow this guide, you need: - a [PostgreSQL](https://www.postgresql.org/) database server running - the [`createdb`](https://www.postgresql.org/docs/9.1/app-createdb.html) command line utility -- the [`psql`]( ) command line client for PostgreSQL +- the [`psql`]() command line client for PostgreSQL - [Node.js](https://nodejs.org/) installed on your machine ## 1. Create a new database and project directory @@ -30,7 +30,7 @@ mkdir check-demo cd check-demo ``` -Next, make sure that your PostgreSQL database server is running. Authenticate the default `postgres` user: +Next, make sure that your PostgreSQL database server is running. Authenticate the default `postgres` user: Unix (bash): @@ -59,7 +59,7 @@ create database CheckDemo; \connect CheckDemo ``` -> *Tip*: Remember the trailing `;`! `postgres=#` `postgres-#` +> _Tip_: Remember the trailing `;`! `postgres=#` `postgres-#` You can validate that the database was created by running the `\dt` command which lists all tables (_relations_) in your database (right now there are none): @@ -67,7 +67,7 @@ Unix (bash): ``` psql -d CheckDemo -c "\dt" -``` +``` Windows (command line): @@ -85,8 +85,8 @@ Create a new file called `single-column-check-constraint.sql` and add the follow CREATE TABLE "public"."product" ( price NUMERIC CONSTRAINT price_value_check CHECK (price > 0.01 AND price <> 1240.00) ); -ALTER TABLE "public"."product" - ADD COLUMN "productid" serial, +ALTER TABLE "public"."product" + ADD COLUMN "productid" serial, ADD PRIMARY KEY ("productid"); ``` @@ -106,8 +106,8 @@ Windows (command line): Congratulations, you just created a table called `product` in the database. The table has one column called `price`, which has a single check constraint that ensures price of a product is: -* Never less than 0.01 -* Never equal to 1240.00 +- Never less than 0.01 +- Never equal to 1240.00 Run the following command to see the a list of check constraints that apply to the `product` table: @@ -140,7 +140,7 @@ CREATE TABLE "public"."anotherproduct" ( price NUMERIC ); ALTER TABLE "public"."anotherproduct" - ADD COLUMN "productid" serial, + ADD COLUMN "productid" serial, ADD PRIMARY KEY ("productid"); ``` @@ -173,7 +173,7 @@ Create a new file called `multiple-check-constraints.sql` and add the following tags TEXT[] CONSTRAINT tags_contains_product CHECK ('product' = ANY(tags)) ); ALTER TABLE "public"."secondtolastproduct" - ADD COLUMN "productid" serial, + ADD COLUMN "productid" serial, ADD PRIMARY KEY ("productid"); ``` @@ -193,8 +193,8 @@ Windows (command line): Congratulations, you just created a table called `lastproduct` in the database. The table has three colums named `reducedprice`, `price` and `tags`, and the following check constraints: -* The `tags` column (which is an array) must contain a tag named `product` -* The value of `reducedprice` must be less than the value of `price` +- The `tags` column (which is an array) must contain a tag named `product` +- The value of `reducedprice` must be less than the value of `price` ## 5. Adding a check constraint to an existing table @@ -207,7 +207,7 @@ CREATE TABLE "public"."lastproduct" ( category TEXT ); -ALTER TABLE "public"."lastproduct" +ALTER TABLE "public"."lastproduct" ADD CONSTRAINT "category_not_clothing" CHECK (category <> 'clothing'); ``` @@ -323,7 +323,7 @@ model secondtolastproduct { To validate whether the check constraints work, you'll now generate Prisma Client and send a few sample queries to the database. -First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): +First, add a `generator` block to your Prisma schema (typically added right below the `datasource` block): ```prisma generator client { @@ -344,23 +344,21 @@ Now you can use Prisma Client to send database queries in Node.js. Create a new file called `index.js` and add the following code to it: ```js -const { PrismaClient } = require('@prisma/client') +const { PrismaClient } = require("@prisma/client"); -const prisma = new PrismaClient() +const prisma = new PrismaClient(); async function main() { - const newProduct = await prisma.product.create({ data: { - price: 0.00 - } + price: 0.0, + }, }); console.log(newProduct); - } -main() +main(); ``` In this code, you're creating a product with a price of `0.00`, which does not meet the check constraint configured for the `price` column. @@ -381,24 +379,22 @@ ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error To validate the multi-column check constraint, replace the code in `index.js` with the following: ```js -const { PrismaClient } = require('@prisma/client') +const { PrismaClient } = require("@prisma/client"); -const prisma = new PrismaClient() +const prisma = new PrismaClient(); async function main() { - const newProduct = await prisma.anotherproduct.create({ data: { - price: 50.00, - reducedprice: 100.00 - } + price: 50.0, + reducedprice: 100.0, + }, }); console.log(newProduct); - } -main() +main(); ``` In this code, you're creating a product where the reduced price is higher than the actual price. @@ -419,27 +415,25 @@ ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error Finally, modify the script to include multiple check constraint violations: ```js -const { PrismaClient } = require('@prisma/client') +const { PrismaClient } = require("@prisma/client"); -const prisma = new PrismaClient() +const prisma = new PrismaClient(); async function main() { - const newProduct = await prisma.secondtolastproduct.create({ data: { tags: { - set: [ "wrongtag" ] - }, - price: 90.00, - reducedprice: 100.00 - } + set: ["wrongtag"], + }, + price: 90.0, + reducedprice: 100.0, + }, }); console.log(newProduct); - } -main() +main(); ``` In this code, you're creating a product where the reduced price is higher than the actual price, and omitting the required `product` tag. @@ -456,4 +450,4 @@ Notice that the error message only mentions the `reduced_price_check` constraint ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: Db, cause: Some(DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState("23514"), message: "new row for relation \"secondtolastproduct\" violates check constraint \"reduced_price_check\"", detail: Some("Failing row contains (100, 90, {wrongtag}, 7)."), hint: None, position: None, where_: None, schema: Some("public"), table: Some("secondtolastproduct"), column: None, datatype: None, constraint: Some("reduced_price_check"), file: Some("d:\\pginstaller_12.auto\\postgres.windows-x64\\src\\backend\\executor\\execmain.c"), line: Some(2023), routine: Some("ExecConstraints") }) }) }) ``` -Check constraints are resolved in alphabetical order, and only the first constraint to fail appears in the error message. \ No newline at end of file +Check constraints are resolved in alphabetical order, and only the first constraint to fail appears in the error message. diff --git a/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx b/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx index f336097fb9..f7bc09159e 100644 --- a/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx @@ -5,6 +5,3 @@ metaDescription: "" --- Coming 🔜 - - - diff --git a/content/04-guides/01-database-workflows/07-data-validation/index.mdx b/content/04-guides/01-database-workflows/07-data-validation/index.mdx index 94cc322b4d..f0d25c081a 100644 --- a/content/04-guides/01-database-workflows/07-data-validation/index.mdx +++ b/content/04-guides/01-database-workflows/07-data-validation/index.mdx @@ -1,4 +1,4 @@ --- title: "Data validation" metaTitle: "" ---- \ No newline at end of file +--- diff --git a/content/04-guides/01-database-workflows/index.mdx b/content/04-guides/01-database-workflows/index.mdx index 749172b6c6..2b10eb4461 100644 --- a/content/04-guides/01-database-workflows/index.mdx +++ b/content/04-guides/01-database-workflows/index.mdx @@ -1,5 +1,5 @@ --- - title: "Database workflows" - metaTitle: "Guides" - staticLink: true ---- \ No newline at end of file +title: "Database workflows" +metaTitle: "Guides" +staticLink: true +--- diff --git a/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx b/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx index ec7afee84b..388005d51f 100644 --- a/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx +++ b/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx @@ -5,4 +5,3 @@ metaDescription: "" --- Coming 🔜 - diff --git a/content/04-guides/02-deployment/03-deploying-to-heroku.mdx b/content/04-guides/02-deployment/03-deploying-to-heroku.mdx index fe82553ea2..d48641389d 100644 --- a/content/04-guides/02-deployment/03-deploying-to-heroku.mdx +++ b/content/04-guides/02-deployment/03-deploying-to-heroku.mdx @@ -5,4 +5,3 @@ metaDescription: "" --- Coming 🔜 - diff --git a/content/04-guides/02-deployment/index.mdx b/content/04-guides/02-deployment/index.mdx index 6cbd508dab..09054af8f6 100644 --- a/content/04-guides/02-deployment/index.mdx +++ b/content/04-guides/02-deployment/index.mdx @@ -1,6 +1,6 @@ --- - title: "Deployment" - metaTitle: "" - metaDescription: "" - staticLink: true ---- \ No newline at end of file +title: "Deployment" +metaTitle: "" +metaDescription: "" +staticLink: true +--- diff --git a/content/04-guides/index.mdx b/content/04-guides/index.mdx index 95431415b4..c268a140da 100644 --- a/content/04-guides/index.mdx +++ b/content/04-guides/index.mdx @@ -1,5 +1,5 @@ --- - title: "Guides" - metaTitle: "Guides" - metaDescription: "Guides" ---- \ No newline at end of file +title: "Guides" +metaTitle: "Guides" +metaDescription: "Guides" +--- diff --git a/package.json b/package.json index 9621282885..3bd9261102 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "scripts": { "build": "gatsby build --prefix-paths", "dev": "gatsby develop", - "prettify": "prettier --write \"src/**/*.css\" \"src/**/*.ts\" \"src/**/*.tsx\"", + "prettify": "prettier --write \"src/**/*.css\" \"src/**/*.ts\" \"src/**/*.tsx\" \"content/**/*.mdx\"", "test": "jest" }, "devDependencies": { diff --git a/src/components/customMdx/code.tsx b/src/components/customMdx/code.tsx index 3eee865817..9fd8759e6e 100644 --- a/src/components/customMdx/code.tsx +++ b/src/components/customMdx/code.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import styled from 'styled-components'; +import React from "react"; +import styled from "styled-components"; interface CodeProps { languages?: string[]; @@ -20,7 +20,7 @@ const CodeBlock = ({ languages, children, ...props }: CodeBlockProps) => { const setCurrentActive = () => setActiveIndex(index); return (
{ +const CopyButton = ({ text, children, ...props }: CopyButtonProps) => { const [copied, setCopied] = React.useState(false); let copyTimer: any; const onCopyContent = () => { - setCopied(true) - copyTimer = window.setTimeout( - () => setCopied(false), - 500, - ) - } + setCopied(true); + copyTimer = window.setTimeout(() => setCopied(false), 500); + }; return ( - - {copied && ( -
- Copied -
- )} - {children} -
-
+ + {copied && ( +
+ Copied +
+ )} + {children} +
+ ); }; export default CopyButton; const CopyComponent = styled.div` - font-family: 'Open Sans'; + font-family: "Open Sans"; & { position: relative; cursor: pointer; @@ -63,4 +60,4 @@ const CopyComponent = styled.div` transform: translate(-50%, 0); animation: copying 700ms linear; } -` +`; diff --git a/src/components/customMdx/index.tsx b/src/components/customMdx/index.tsx index c992837ce8..92308a21c8 100644 --- a/src/components/customMdx/index.tsx +++ b/src/components/customMdx/index.tsx @@ -1,49 +1,25 @@ -import React from 'react'; -import CodeBlock from './code'; -import Pre from './pre'; +import React from "react"; +import CodeBlock from "./code"; +import Pre from "./pre"; export default { h1: (props: any) => ( -

+

), h2: (props: any) => ( -

+

), h3: (props: any) => ( -

+

), h4: (props: any) => ( -

+

), h5: (props: any) => ( -

+
), h6: (props: any) => ( -
+
), p: (props: any) =>

, ul: (props: any) =>

    , diff --git a/src/components/customMdx/pre.tsx b/src/components/customMdx/pre.tsx index c2a7685d24..b5ff12cc82 100644 --- a/src/components/customMdx/pre.tsx +++ b/src/components/customMdx/pre.tsx @@ -1,17 +1,17 @@ -import React from 'react'; -import styled from 'styled-components'; -import CopyButton from './copy'; -import Copy from '../../icons/Copy'; -import { stringify } from '../../utils/stringify'; +import React from "react"; +import styled from "styled-components"; +import CopyButton from "./copy"; +import Copy from "../../icons/Copy"; +import { stringify } from "../../utils/stringify"; type PreBlockProps = React.ReactNode; const getSettings = (className: any) => { let copy = false; if (className) { - const split = className.split('-'); + const split = className.split("-"); if (split.length > 1) { - copy = split[1].substr(split.length - 6) === 'copy'; + copy = split[1].substr(split.length - 6) === "copy"; } } return copy; @@ -26,7 +26,9 @@ const Pre = ({ languages, children, ...props }: PreBlockProps) => { {children} {copy && ( - + + + )} diff --git a/src/components/footer.tsx b/src/components/footer.tsx index 4ffb0fdcc2..62b050e2c5 100644 --- a/src/components/footer.tsx +++ b/src/components/footer.tsx @@ -1,16 +1,16 @@ -import { Link } from 'gatsby'; -import * as React from 'react'; -import styled from 'styled-components'; -import PrismaLogoGrey from '../icons/PrismaLogoGrey'; -import Email from '../icons/Email'; -import ArrowEmail from '../icons/ArrowEmail'; -import Twitter from '../icons/Twitter'; -import Youtube from '../icons/Youtube'; -import Slack from '../icons/Slack'; -import Github from '../icons/GitGrey'; -import Facebook from '../icons/Facebook'; - -import { FooterProps } from '../interfaces/Layout.interface'; +import { Link } from "gatsby"; +import * as React from "react"; +import styled from "styled-components"; +import PrismaLogoGrey from "../icons/PrismaLogoGrey"; +import Email from "../icons/Email"; +import ArrowEmail from "../icons/ArrowEmail"; +import Twitter from "../icons/Twitter"; +import Youtube from "../icons/Youtube"; +import Slack from "../icons/Slack"; +import Github from "../icons/GitGrey"; +import Facebook from "../icons/Facebook"; + +import { FooterProps } from "../interfaces/Layout.interface"; type FooterViewProps = { footerProps: FooterProps; @@ -71,8 +71,7 @@ const NewsLetter = styled.div` margin-top: 24px; input { background: #ffffff; - box-shadow: 0px 4px 8px rgba(60, 45, 111, 0.1), - 0px 1px 3px rgba(60, 45, 111, 0.15); + box-shadow: 0px 4px 8px rgba(60, 45, 111, 0.1), 0px 1px 3px rgba(60, 45, 111, 0.15); border-radius: 5px; width: 100%; border: 0; @@ -120,12 +119,12 @@ const Footer = ({ footerProps }: FooterViewProps) => { } = footerProps; return ( -
    +
    @@ -178,11 +177,9 @@ const Footer = ({ footerProps }: FooterViewProps) => {

    {newsletter.text}

    - + - +

    FIND US

    diff --git a/src/components/header.tsx b/src/components/header.tsx index 732cd67bbc..2ead889fd4 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -1,10 +1,10 @@ -import { Link } from 'gatsby'; -import * as React from 'react'; -import styled from 'styled-components'; -import HeaderLogo from '../icons/Logo'; -import Github from '../icons/Git'; -import Search from '../icons/Search'; -import { HeaderProps } from '../interfaces/Layout.interface'; +import { Link } from "gatsby"; +import * as React from "react"; +import styled from "styled-components"; +import HeaderLogo from "../icons/Logo"; +import Github from "../icons/Git"; +import Search from "../icons/Search"; +import { HeaderProps } from "../interfaces/Layout.interface"; type HeaderViewProps = { headerProps: HeaderProps; @@ -51,8 +51,7 @@ const SearchInput = styled.input` max-width: 208px; width: 18%; background: #ffffff; - box-shadow: 0px 4px 8px rgba(60, 45, 111, 0.1), - 0px 1px 3px rgba(60, 45, 111, 0.15); + box-shadow: 0px 4px 8px rgba(60, 45, 111, 0.1), 0px 1px 3px rgba(60, 45, 111, 0.15); border-radius: 5px; padding: 0.6rem 2.5rem; font-family: Open Sans; @@ -91,16 +90,16 @@ const NavLinks = styled.div` const Header = ({ headerProps }: HeaderViewProps) => ( -
    +
    - + {headerProps.title} @@ -111,8 +110,8 @@ const Header = ({ headerProps }: HeaderViewProps) => ( key={index} to={headerlink.link} style={{ - color: 'white', - textDecoration: 'none', + color: "white", + textDecoration: "none", }} > {headerlink.name} @@ -120,17 +119,17 @@ const Header = ({ headerProps }: HeaderViewProps) => ( ))} - + -
    - +
    +
    diff --git a/src/components/image.tsx b/src/components/image.tsx index 9d948f0083..b5ad4ef6f5 100644 --- a/src/components/image.tsx +++ b/src/components/image.tsx @@ -1,6 +1,6 @@ -import { graphql, useStaticQuery } from 'gatsby'; -import Img from 'gatsby-image'; -import * as React from 'react'; +import { graphql, useStaticQuery } from "gatsby"; +import Img from "gatsby-image"; +import * as React from "react"; /* * This component is built using `gatsby-image` to automatically serve optimized diff --git a/src/components/layout.css b/src/components/layout.css index 72d38956d2..030f64c449 100644 --- a/src/components/layout.css +++ b/src/components/layout.css @@ -1,7 +1,7 @@ -@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,600|Montserrat:400,700|Rubik:400,500|Roboto+Mono:400,500,700&display=swap'); +@import url("https://fonts.googleapis.com/css?family=Open+Sans:400,600|Montserrat:400,700|Rubik:400,500|Roboto+Mono:400,500,700&display=swap"); html { - font-family: 'Open Sans', sans-serif; + font-family: "Open Sans", sans-serif; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; box-sizing: border-box; @@ -11,7 +11,7 @@ html { body { margin: 0; background-color: #f7fafc; - font-family: 'Open Sans', sans-serif; + font-family: "Open Sans", sans-serif; font-weight: normal; word-wrap: break-word; color: #1a202c; @@ -26,7 +26,7 @@ h3, h4, h5, h6 { - font-family: 'Open Sans', sans-serif; + font-family: "Open Sans", sans-serif; font-weight: 500; } @@ -37,7 +37,7 @@ h6 { .heading2:focus::before, .heading2:hover::before { - content: '#'; + content: "#"; margin-left: -20px; margin-right: 5px; color: #cbd5e0; @@ -66,7 +66,7 @@ p { p, li { - font-family: 'Open Sans'; + font-family: "Open Sans"; font-style: normal; font-weight: normal; font-size: 16px; @@ -94,9 +94,9 @@ table td { border-top: 1px solid rgb(204, 217, 223); } -:not(pre) > code[class*='language-text'], -pre[class*='language-text'] { - font-family: 'Roboto Mono'; +:not(pre) > code[class*="language-text"], +pre[class*="language-text"] { + font-family: "Roboto Mono"; font-style: normal; font-weight: 500; font-size: 14px; @@ -107,7 +107,7 @@ pre[class*='language-text'] { padding: 4px 6px; } -pre[class*='language-'] { +pre[class*="language-"] { background: #f7fafc; border-radius: 8px; display: inline-block; @@ -116,8 +116,8 @@ pre[class*='language-'] { white-space: pre-wrap; } -code[class*='language-'] { - font-family: 'Roboto Mono'; +code[class*="language-"] { + font-family: "Roboto Mono"; font-style: normal; font-weight: normal; font-size: 14px; @@ -149,7 +149,7 @@ hr { } .list li::before { - content: '\2022'; + content: "\2022"; color: #a0aec0; font-weight: bold; font-size: 28px; diff --git a/src/components/layout.tsx b/src/components/layout.tsx index 8cdc277663..4d1c5a8dd4 100644 --- a/src/components/layout.tsx +++ b/src/components/layout.tsx @@ -1,29 +1,26 @@ -import { RouterProps } from '@reach/router'; -import * as React from 'react'; -import styled, { ThemeProvider } from 'styled-components'; -import { useLayoutQuery } from '../hooks/useLayoutQuery'; -import Header from './header'; -import Footer from './footer'; +import { RouterProps } from "@reach/router"; +import * as React from "react"; +import styled, { ThemeProvider } from "styled-components"; +import { useLayoutQuery } from "../hooks/useLayoutQuery"; +import Header from "./header"; +import Footer from "./footer"; -import { MDXProvider } from '@mdx-js/react'; -import customMdx from '../components/customMdx'; -import './layout.css'; -import Sidebar from './sidebar'; +import { MDXProvider } from "@mdx-js/react"; +import customMdx from "../components/customMdx"; +import "./layout.css"; +import Sidebar from "./sidebar"; interface ThemeProps { colorPrimary: string; } const theme: ThemeProps = { - colorPrimary: '#663399', + colorPrimary: "#663399", }; type LayoutProps = React.ReactNode & RouterProps; -const Layout: React.FunctionComponent = ({ - children, - location, -}) => { +const Layout: React.FunctionComponent = ({ children, location }) => { const { site } = useLayoutQuery(); const { header, footer } = site.siteMetadata; @@ -64,7 +61,7 @@ const Layout: React.FunctionComponent = ({
    - + diff --git a/src/components/pageBottom.tsx b/src/components/pageBottom.tsx index 7a152ada77..60f773564c 100644 --- a/src/components/pageBottom.tsx +++ b/src/components/pageBottom.tsx @@ -1,7 +1,7 @@ -import * as React from 'react'; -import styled from 'styled-components'; -import Up from '../icons/Up'; -import Down from '../icons/Down'; +import * as React from "react"; +import styled from "styled-components"; +import Up from "../icons/Up"; +import Down from "../icons/Down"; const PageBottomWrapper = styled.div` display: flex; @@ -33,10 +33,10 @@ const PageBottom = () => (

    Was this helpful?

    diff --git a/src/components/seo.tsx b/src/components/seo.tsx index 49c5c15704..bbeaaabd63 100644 --- a/src/components/seo.tsx +++ b/src/components/seo.tsx @@ -1,5 +1,5 @@ -import * as React from 'react'; -import Helmet from 'react-helmet'; +import * as React from "react"; +import Helmet from "react-helmet"; type SEOProps = { title?: string; diff --git a/src/components/sidebar/index.tsx b/src/components/sidebar/index.tsx index 9109320ee3..f666232f21 100644 --- a/src/components/sidebar/index.tsx +++ b/src/components/sidebar/index.tsx @@ -1,8 +1,8 @@ -import React from 'react'; -import Tree from './tree'; -import styled from 'styled-components'; -import { useAllArticlesQuery } from '../../hooks/useAllArticlesQuery'; -import { AllArticles } from '../../interfaces/AllArticles.interface'; +import React from "react"; +import Tree from "./tree"; +import styled from "styled-components"; +import { useAllArticlesQuery } from "../../hooks/useAllArticlesQuery"; +import { AllArticles } from "../../interfaces/AllArticles.interface"; const Sidebar = styled.aside` margin: 0; diff --git a/src/components/sidebar/tree.tsx b/src/components/sidebar/tree.tsx index 6403cb25b5..081b8c7f54 100644 --- a/src/components/sidebar/tree.tsx +++ b/src/components/sidebar/tree.tsx @@ -1,7 +1,7 @@ -import React, { useState } from 'react'; -import TreeNode from './treeNode'; -import { AllEdges } from '../../interfaces/AllArticles.interface'; -import { ArticleFields } from '../../interfaces/Article.interface'; +import React, { useState } from "react"; +import TreeNode from "./treeNode"; +import { AllEdges } from "../../interfaces/AllArticles.interface"; +import { ArticleFields } from "../../interfaces/Article.interface"; interface TreeNode { node: { @@ -9,7 +9,6 @@ interface TreeNode { }; } - // TODO::Simplify the function const calculateTreeData = (edges: any) => { let defaultCollapsed: any = {}; @@ -22,13 +21,12 @@ const calculateTreeData = (edges: any) => { }, }: TreeNode ) => { - const parts = slug.split('/'); + const parts = slug.split("/"); + // if(parts.length === 3) {console.log(parts)} let { items: prevItems } = accu; const slicedParts = parts.slice(1, -1); for (const part of slicedParts) { - let tmp = - prevItems && prevItems.find(({ label }: any) => label == part); - + let tmp = prevItems && prevItems.find(({ label }: any) => label == part); if (tmp) { if (!tmp.items) { tmp.items = []; @@ -37,28 +35,22 @@ const calculateTreeData = (edges: any) => { tmp = { label: part, items: [], - topLevel: parts.length == 3 ? true : false, + topLevel: ((parts.length == 3) && (parts[parts.length -1] === 'index')) ? true : false, }; prevItems.push(tmp); } - if ( - parts[parts.length - 1] === 'index' && - parts[parts.length - 2] === part - ) { + if (parts[parts.length - 1] === "index" && parts[parts.length - 2] === part) { tmp.url = slug; tmp.title = title; tmp.staticLink = staticLink; tmp.duration = duration; tmp.experimental = experimental; } - defaultCollapsed[part.toLowerCase()] = - tmp.topLevel || tmp.staticLink ? false : true; + defaultCollapsed[part.toLowerCase()] = tmp.topLevel || tmp.staticLink ? false : true; prevItems = tmp.items; } const slicedLength = parts.length - 1; - const existingItem = prevItems.find( - ({ label }: any) => label === parts[slicedLength] - ); + const existingItem = prevItems.find(({ label }: any) => label === parts[slicedLength]); if (existingItem) { existingItem.url = slug; @@ -79,7 +71,7 @@ const calculateTreeData = (edges: any) => { }, { items: [] } ); - return {tree, defaultCollapsed}; + return { tree, defaultCollapsed }; }; const Tree = ({ edges }: AllEdges) => { @@ -87,13 +79,12 @@ const Tree = ({ edges }: AllEdges) => { return calculateTreeData(edges).tree; }); - // const [collapsed, setCollapsed] = useState(defaultCollapsed); const [collapsed, setCollapsed] = useState(() => { return calculateTreeData(edges).defaultCollapsed; }); - console.log(collapsed) + console.log(treeData); const toggle = (label: string) => { setCollapsed({ diff --git a/src/components/sidebar/treeNode.tsx b/src/components/sidebar/treeNode.tsx index a59b7a097d..9c87d3f974 100644 --- a/src/components/sidebar/treeNode.tsx +++ b/src/components/sidebar/treeNode.tsx @@ -1,9 +1,9 @@ -import React from 'react'; -import config from '../../../config'; -import styled from 'styled-components'; -import './treeNode.css'; -import ArrowRight from '../../icons/ArrowRight'; -import ArrowDown from '../../icons/ArrowDown'; +import React from "react"; +import config from "../../../config"; +import styled from "styled-components"; +import "./treeNode.css"; +import ArrowRight from "../../icons/ArrowRight"; +import ArrowDown from "../../icons/ArrowDown"; const List = styled.ul` list-style: none; @@ -22,7 +22,7 @@ const ListItem = styled.li` `; const TreeNode = ({ - className = '', + className = "", setCollapsed, collapsed, url, @@ -42,17 +42,15 @@ const TreeNode = ({ const hasChildren = items.length !== 0; let location; - if (typeof document != 'undefined') { + if (typeof document != "undefined") { location = document.location; } const active = - location && - (location.pathname === url || - location.pathname === config.gatsby.pathPrefix + url); + location && (location.pathname === url || location.pathname === config.gatsby.pathPrefix + url); - const calculatedClassName = `${className} item ${active ? 'active' : ''} ${ - topLevel ? 'top-level' : '' - } ${staticLink ? 'static-link' : ''}`; + const calculatedClassName = `${className} item ${active ? "active" : ""} ${ + topLevel ? "top-level" : "" + } ${staticLink ? "static-link" : ""}`; items.sort((a: any, b: any) => { if (a.label < b.label) { @@ -66,14 +64,10 @@ const TreeNode = ({ return ( - {title && label !== 'index' && ( - + {title && label !== "index" && ( + {title && hasChildren && !staticLink && !topLevel ? ( - ) : null} diff --git a/src/components/toc.tsx b/src/components/toc.tsx index 567f391165..b2effe479a 100644 --- a/src/components/toc.tsx +++ b/src/components/toc.tsx @@ -1,14 +1,14 @@ -import React from 'react'; -import styled from 'styled-components'; -import { AllArticlesTOC } from '../interfaces/TOC.interface'; -import { useTOCQuery } from '../hooks/useTOCQuery'; +import React from "react"; +import styled from "styled-components"; +import { AllArticlesTOC } from "../interfaces/TOC.interface"; +import { useTOCQuery } from "../hooks/useTOCQuery"; const TOCContent = styled.aside` // padding: 2rem 0 0; `; const ChapterTitle = styled.h1` - font-family: 'Open Sans'; + font-family: "Open Sans"; font-style: normal; font-weight: bold; font-size: 14px; @@ -26,22 +26,20 @@ const TOC = ({ location }: any) => { if (item !== undefined) { if ( item.node.fields.slug === location.pathname || - '/' + item.node.fields.slug === location.pathname + "/" + item.node.fields.slug === location.pathname ) { if (item.node.tableOfContents.items) { - navItems = item.node.tableOfContents.items.map( - (innerItem: any, index: number) => { - const itemId = innerItem.title - ? innerItem.title.replace(/\s+/g, '-').toLowerCase() - : '#'; + navItems = item.node.tableOfContents.items.map((innerItem: any, index: number) => { + const itemId = innerItem.title + ? innerItem.title.replace(/\s+/g, "-").toLowerCase() + : "#"; - return ( -
  • - {innerItem.title} -
  • - ); - } - ); + return ( +
  • + {innerItem.title} +
  • + ); + }); } } } @@ -50,9 +48,7 @@ const TOC = ({ location }: any) => { return navItems && navItems.length ? ( CONTENT -
      - {navItems} -
    +
      {navItems}
    ) : null; }; diff --git a/src/components/topSection.tsx b/src/components/topSection.tsx index e11f8f8418..a3b8808483 100644 --- a/src/components/topSection.tsx +++ b/src/components/topSection.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; -import styled from 'styled-components'; -import TOC from './toc'; +import * as React from "react"; +import styled from "styled-components"; +import TOC from "./toc"; const BreadcrumbTitle = styled.h4` color: #718096; @@ -9,7 +9,7 @@ const BreadcrumbTitle = styled.h4` `; const MainTitle = styled.h1` - font-family: 'Montserrat'; + font-family: "Montserrat"; font-style: normal; font-weight: bold; letter-spacing: -0.02em; diff --git a/src/hooks/useAllArticlesQuery.ts b/src/hooks/useAllArticlesQuery.ts index 1534d1bec0..644b096425 100644 --- a/src/hooks/useAllArticlesQuery.ts +++ b/src/hooks/useAllArticlesQuery.ts @@ -1,5 +1,5 @@ -import { graphql, useStaticQuery } from 'gatsby'; -import { AllArticles } from '../interfaces/AllArticles.interface'; +import { graphql, useStaticQuery } from "gatsby"; +import { AllArticles } from "../interfaces/AllArticles.interface"; export const useAllArticlesQuery = () => { const { allMdx }: AllArticles = useStaticQuery(graphql` diff --git a/src/hooks/useLayoutQuery.ts b/src/hooks/useLayoutQuery.ts index 57050a26cb..67fb59340a 100644 --- a/src/hooks/useLayoutQuery.ts +++ b/src/hooks/useLayoutQuery.ts @@ -1,5 +1,5 @@ -import { graphql, useStaticQuery } from 'gatsby'; -import { LayoutQueryData } from '../interfaces/Layout.interface'; +import { graphql, useStaticQuery } from "gatsby"; +import { LayoutQueryData } from "../interfaces/Layout.interface"; export const useLayoutQuery = () => { const { site }: LayoutQueryData = useStaticQuery(graphql` diff --git a/src/hooks/useTOCQuery.ts b/src/hooks/useTOCQuery.ts index 7808cdac51..be5bde6c4a 100644 --- a/src/hooks/useTOCQuery.ts +++ b/src/hooks/useTOCQuery.ts @@ -1,5 +1,5 @@ -import { graphql, useStaticQuery } from 'gatsby'; -import { AllArticlesTOC } from '../interfaces/TOC.interface'; +import { graphql, useStaticQuery } from "gatsby"; +import { AllArticlesTOC } from "../interfaces/TOC.interface"; export const useTOCQuery = () => { const { allMdx }: AllArticlesTOC = useStaticQuery(graphql` diff --git a/src/icons/ArrowDown.tsx b/src/icons/ArrowDown.tsx index 93ab45dfee..34a2693e38 100644 --- a/src/icons/ArrowDown.tsx +++ b/src/icons/ArrowDown.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; export default (props: any) => ( ( ( ( ( - + ( ( - + ( ( - + ( ( - + ( ( - + ( - + ( - + ( - + ]; diff --git a/src/interfaces/Article.interface.ts b/src/interfaces/Article.interface.ts index 74cb07776f..529490f55e 100644 --- a/src/interfaces/Article.interface.ts +++ b/src/interfaces/Article.interface.ts @@ -1,4 +1,4 @@ -import { AllEdges } from './AllArticles.interface'; +import { AllEdges } from "./AllArticles.interface"; export interface ArticleFields { slug: string; diff --git a/src/interfaces/Layout.interface.ts b/src/interfaces/Layout.interface.ts index 7f1ec229a6..3518e02419 100644 --- a/src/interfaces/Layout.interface.ts +++ b/src/interfaces/Layout.interface.ts @@ -31,4 +31,3 @@ interface SiteMeta { export interface LayoutQueryData { site: SiteMeta; } - diff --git a/src/interfaces/TOC.interface.ts b/src/interfaces/TOC.interface.ts index a278e0d532..6ef9d08ded 100644 --- a/src/interfaces/TOC.interface.ts +++ b/src/interfaces/TOC.interface.ts @@ -1,4 +1,4 @@ -import { EdgeNode } from './EdgeNode.interface'; +import { EdgeNode } from "./EdgeNode.interface"; export interface AllArticlesTOC { allMdx: AllEdgesTOC; diff --git a/src/layouts/articleLayout.tsx b/src/layouts/articleLayout.tsx index 4ee4f68217..1ebe7241a9 100644 --- a/src/layouts/articleLayout.tsx +++ b/src/layouts/articleLayout.tsx @@ -1,21 +1,20 @@ -import { RouterProps } from '@reach/router'; -import * as React from 'react'; -import { ArticleQueryData } from '../interfaces/Article.interface'; -import Layout from '../components/layout'; -import TopSection from '../components/topSection'; -import PageBottom from '../components/pageBottom'; -import SEO from '../components/seo'; -import { graphql } from 'gatsby'; -import MDXRenderer from 'gatsby-plugin-mdx/mdx-renderer'; +import { RouterProps } from "@reach/router"; +import * as React from "react"; +import { ArticleQueryData } from "../interfaces/Article.interface"; +import Layout from "../components/layout"; +import TopSection from "../components/topSection"; +import PageBottom from "../components/pageBottom"; +import SEO from "../components/seo"; +import { graphql } from "gatsby"; +import MDXRenderer from "gatsby-plugin-mdx/mdx-renderer"; -import styled from 'styled-components'; +import styled from "styled-components"; type ArticleLayoutProps = ArticleQueryData & RouterProps; const BlockContent = styled.div` background: #ffffff; - box-shadow: 0px 4px 8px rgba(47, 55, 71, 0.05), - 0px 1px 3px rgba(47, 55, 71, 0.1); + box-shadow: 0px 4px 8px rgba(47, 55, 71, 0.05), 0px 1px 3px rgba(47, 55, 71, 0.1); border-radius: 5px; margin-top: 1rem; padding: 40px; @@ -35,37 +34,31 @@ const ArticleLayout = ({ data, ...props }: ArticleLayoutProps) => { } = data; // Parent title extraction - const allContent = - allMdx && allMdx.edges && allMdx.edges.map((mdx: any) => mdx.node.fields); + const allContent = allMdx && allMdx.edges && allMdx.edges.map((mdx: any) => mdx.node.fields); allContent?.map((content: any) => { - content.parentTitle = ''; - const parts = content.slug.split('/'); + content.parentTitle = ""; + const parts = content.slug.split("/"); const slicedParts = parts.slice(1, parts.length - 1); slicedParts.forEach((part: any) => { const parent = allContent.find(ac => { - const parentParts = ac.slug.split('/'); + const parentParts = ac.slug.split("/"); return ( - parentParts[parentParts.length - 1] === 'index' && + parentParts[parentParts.length - 1] === "index" && parentParts[parentParts.length - 2] === part ); }); - content.parentTitle = content.parentTitle + parent?.title + ' / '; + content.parentTitle = content.parentTitle + parent?.title + " / "; }); }); - const getParentTitle = () => - allContent?.find(mdx => mdx.slug === slug).parentTitle.slice(0, -2); + const getParentTitle = () => allContent?.find(mdx => mdx.slug === slug).parentTitle.slice(0, -2); return ( - + {body} diff --git a/src/pages/404.tsx b/src/pages/404.tsx index d9ff9eaeab..02411db05f 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,5 +1,5 @@ -import * as React from 'react'; -import Layout from '../components/layout'; +import * as React from "react"; +import Layout from "../components/layout"; const NotFoundPage = () => ( diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 8488beab2e..31f3c12725 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,11 +1,11 @@ -import { Link } from 'gatsby'; -import React from 'react'; -import styled from 'styled-components'; -import Helmet from 'react-helmet'; -import config from '../../config'; -import Layout from '../components/layout'; -import TopSection from '../components/topSection'; -import SEO from '../components/seo'; +import { Link } from "gatsby"; +import React from "react"; +import styled from "styled-components"; +import Helmet from "react-helmet"; +import config from "../../config"; +import Layout from "../components/layout"; +import TopSection from "../components/topSection"; +import SEO from "../components/seo"; // const Container = styled.span` // font-family: 'Rubik', sans-serif; @@ -20,8 +20,7 @@ import SEO from '../components/seo'; const BlockContent = styled.div` background: #ffffff; - box-shadow: 0px 4px 8px rgba(47, 55, 71, 0.05), - 0px 1px 3px rgba(47, 55, 71, 0.1); + box-shadow: 0px 4px 8px rgba(47, 55, 71, 0.05), 0px 1px 3px rgba(47, 55, 71, 0.1); border-radius: 5px; margin-top: 1rem; padding: 40px; @@ -36,11 +35,7 @@ export default function DocHome({ ...props }: any) { keywords={config.siteMetadata.keywords || undefined} /> - + ); diff --git a/src/utils/stringify.ts b/src/utils/stringify.ts index f1a9961cbf..dcef2fe0f2 100644 --- a/src/utils/stringify.ts +++ b/src/utils/stringify.ts @@ -1,41 +1,41 @@ export function stringify(children: any): string { - if (typeof children === 'string') { - return children - } - - if (typeof children === 'undefined') { - return '' - } - - if (children === null) { - return '' - } - - if (children.props && children.props.children) { - children = children.props.children - } - if (children.props && children.props.children) { - children = children.props.children - } - - /** - * Necessary because now the pointer changed!!!! - */ - if (typeof children === 'string') { - return children - } - - if (Array.isArray(children)) { - return children - .map(el => { - if (typeof el === 'string') { - return el - } else { - return stringify(el) - } - }) - .join('') - } - - return '' - } \ No newline at end of file + if (typeof children === "string") { + return children; + } + + if (typeof children === "undefined") { + return ""; + } + + if (children === null) { + return ""; + } + + if (children.props && children.props.children) { + children = children.props.children; + } + if (children.props && children.props.children) { + children = children.props.children; + } + + /** + * Necessary because now the pointer changed!!!! + */ + if (typeof children === "string") { + return children; + } + + if (Array.isArray(children)) { + return children + .map(el => { + if (typeof el === "string") { + return el; + } else { + return stringify(el); + } + }) + .join(""); + } + + return ""; +} From 71b314c8db21fb848f36b07122f51b9939a3891e Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Fri, 20 Mar 2020 19:34:27 +0100 Subject: [PATCH 11/33] try to fix build --- .../01-tools-and-interfaces/01-schema/04-data-model.mdx | 4 ++-- .../01-tools-and-interfaces/02-prisma-client/03-crud.mdx | 6 ++++-- .../01-tools-and-interfaces/02-prisma-client/12-logging.mdx | 4 ++-- .../02-importing-and-exporting-data/index.mdx | 4 ++-- .../04-unique-constraints-and-indexes/01-postgresql.mdx | 4 ++-- .../04-unique-constraints-and-indexes/02-mysql.mdx | 4 ++-- .../04-unique-constraints-and-indexes/03-sqlite.mdx | 4 ++-- .../01-database-workflows/05-foreign-keys/01-postgresql.mdx | 4 ++-- .../01-database-workflows/05-foreign-keys/03-sqlite.mdx | 4 ++-- .../06-cascading-deletes/01-postgresql.mdx | 4 ++-- .../01-database-workflows/06-cascading-deletes/02-mysql.mdx | 4 ++-- .../06-cascading-deletes/03-sqlite.mdx | 3 ++- 12 files changed, 26 insertions(+), 23 deletions(-) diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx index 704ec10d8e..8bdb5d1c23 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx @@ -110,7 +110,7 @@ You can use the following scalar types in the Prisma data model: The _data source connector_ determines what _native database type_ each of these types map to. Similarly, the _generator_ determines what _type in the target programming language_ each of these types map to. Expand below to see the mappings per connector and generator. - + ## Enums diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-crud.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-crud.mdx index ce9e6521c8..d7088df111 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-crud.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-crud.mdx @@ -85,7 +85,7 @@ export type UserWhereUniqueInput = { email?: string | null } ``` - + #### Reference @@ -567,6 +567,7 @@ export type UserWhereUniqueInput = { } ``` + #### Reference diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/12-logging.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/12-logging.mdx index 2a9b125f63..bbe998b5ac 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/12-logging.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/12-logging.mdx @@ -139,7 +139,7 @@ export type QueryEvent = { ``` Note that `query` contains the SQL query and `params` contains any query parameters for the SQL query. - + #### Logging `info` events diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx index 747420cef0..547fd1bdbc 100644 --- a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx @@ -1,4 +1,4 @@ --- -title: "Importing and exporting data"" -metaTitle: "" +title: "Importing and exporting data" +metaTitle: "Importing and exporting data" --- \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/01-postgresql.mdx b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/01-postgresql.mdx index be5fd33e3e..03af78871f 100644 --- a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/01-postgresql.mdx @@ -67,7 +67,7 @@ Congratulations, you just created a table called `User` in the database. The tab ```sql CREATE UNIQUE INDEX "User_email_key" ON "User"(email text_ops); ``` - + ## 3. Create a table with a multi-column unique constraint and index diff --git a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/02-mysql.mdx b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/02-mysql.mdx index 083dd5c4e3..1f0c40953a 100644 --- a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/02-mysql.mdx @@ -79,7 +79,7 @@ Congratulations, you just created a table called `User` in the database. The tab ```sql CREATE UNIQUE INDEX `email` ON `UniqueDemo`.`User`(`email`); ``` - + ## 3. Create a table with a multi-column unique constraint and index diff --git a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/03-sqlite.mdx b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/03-sqlite.mdx index f515e9b9cd..464375ca5f 100644 --- a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/03-sqlite.mdx +++ b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/03-sqlite.mdx @@ -67,7 +67,7 @@ Congratulations, you just created a table called `User` in the database. The tab ```sql CREATE UNIQUE INDEX "sqlite_autoindex_User_1" ON "User"("email"); ``` - + ## 3. Create a table with a multi-column unique constraint and index diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/01-postgresql.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/01-postgresql.mdx index b9fb069238..0d6198ef29 100644 --- a/content/04-guides/01-database-workflows/05-foreign-keys/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/05-foreign-keys/01-postgresql.mdx @@ -69,7 +69,7 @@ psql ForeignKeyDemo < single-column-foreign-key.sql ``` Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. - + ## 3. Create a table with a multi-column foreign key constraint diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/03-sqlite.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/03-sqlite.mdx index d46cda0b6b..5627adbf7e 100644 --- a/content/04-guides/01-database-workflows/05-foreign-keys/03-sqlite.mdx +++ b/content/04-guides/01-database-workflows/05-foreign-keys/03-sqlite.mdx @@ -67,7 +67,7 @@ sqlite3 ForeignKeyDemo.db < single-column-foreign-key.sql ``` Congratulations, you just created two tables called `User` and `Post` in the database. The `Post` table references the `User` table via the foreign key defined on the `author` column. - + ## 3. Create a table with a multi-column foreign key constraint diff --git a/content/04-guides/01-database-workflows/06-cascading-deletes/01-postgresql.mdx b/content/04-guides/01-database-workflows/06-cascading-deletes/01-postgresql.mdx index efd707ca51..159633dc38 100644 --- a/content/04-guides/01-database-workflows/06-cascading-deletes/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/06-cascading-deletes/01-postgresql.mdx @@ -86,7 +86,7 @@ The deletion bevahior `RESCTRICT` in this case means that it is not possible to update or delete on table "User" violates foreign key constraint "Post_author_fkey" on table "Post" Detail: Key (id)=(1) is still referenced from table "Post". ``` - + ## 3. Create two tables with a foreign key and `CASCADE` deletion behavior diff --git a/content/04-guides/01-database-workflows/06-cascading-deletes/02-mysql.mdx b/content/04-guides/01-database-workflows/06-cascading-deletes/02-mysql.mdx index 38edfd9d8e..d425dc5377 100644 --- a/content/04-guides/01-database-workflows/06-cascading-deletes/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/06-cascading-deletes/02-mysql.mdx @@ -107,7 +107,7 @@ The deletion action `RESTRICT` in this case means that it is not possible to del update or delete on table "User" violates foreign key constraint "Post_author_fkey" on table "Post" Detail: Key (id)=(1) is still referenced from table "Post". ``` - + ## 3. Create two tables with a foreign key and `CASCADE` deletion action diff --git a/content/04-guides/01-database-workflows/06-cascading-deletes/03-sqlite.mdx b/content/04-guides/01-database-workflows/06-cascading-deletes/03-sqlite.mdx index 0c18d14470..7f72e9b3e4 100644 --- a/content/04-guides/01-database-workflows/06-cascading-deletes/03-sqlite.mdx +++ b/content/04-guides/01-database-workflows/06-cascading-deletes/03-sqlite.mdx @@ -85,6 +85,7 @@ update or delete on table "User" violates foreign key constraint "Post_author_fk Detail: Key (id)=(1) is still referenced from table "Post". ``` + ## 3. Create two tables with a foreign key and `CASCADE` deletion behavior From ac040aad1ad3a71e3f655a099026e8fb30482559 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Fri, 20 Mar 2020 19:39:09 +0100 Subject: [PATCH 12/33] fix frontmatter --- .../01-getting-started/01-examples-mdx.mdx | 6 +- .../01-schema/04-data-model.mdx | 47 +- .../02-prisma-client/03-crud.mdx | 419 +++++++++--------- .../02-prisma-client/12-logging.mdx | 139 +++--- .../02-importing-and-exporting-data/index.mdx | 5 +- .../01-postgresql.mdx | 71 +-- .../02-mysql.mdx | 80 ++-- .../03-sqlite.mdx | 68 +-- .../05-foreign-keys/01-postgresql.mdx | 29 +- .../05-foreign-keys/03-sqlite.mdx | 39 +- .../06-cascading-deletes/01-postgresql.mdx | 159 ++++--- .../06-cascading-deletes/02-mysql.mdx | 104 +++-- .../06-cascading-deletes/03-sqlite.mdx | 162 ++++--- src/components/sidebar/tree.tsx | 2 +- 14 files changed, 694 insertions(+), 636 deletions(-) diff --git a/content/01-getting-started/01-examples-mdx.mdx b/content/01-getting-started/01-examples-mdx.mdx index 863b78074c..f57df50b55 100644 --- a/content/01-getting-started/01-examples-mdx.mdx +++ b/content/01-getting-started/01-examples-mdx.mdx @@ -1,7 +1,7 @@ --- - title: "MDX examples" - metaTitle: "" - metaDescription: "" +title: "MDX examples" +metaTitle: "" +metaDescription: "" --- ## Paragraph diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx index 8bdb5d1c23..cd896dbc64 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx @@ -1,7 +1,7 @@ --- - title: "Data model" - metaTitle: "" - metaDescription: "" +title: "Data model" +metaTitle: "" +metaDescription: "" --- ## Overview @@ -110,6 +110,7 @@ You can use the following scalar types in the Prisma data model: The _data source connector_ determines what _native database type_ each of these types map to. Similarly, the _generator_ determines what _type in the target programming language_ each of these types map to. Expand below to see the mappings per connector and generator. + From 70a3832518a07a46d7f12059e744331cea97062b Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sat, 21 Mar 2020 18:10:02 +0100 Subject: [PATCH 18/33] add queries for profile --- content/01-getting-started/02-quickstart.mdx | 46 +++++++++---------- .../02-start-from-scratch-sql-migrations.mdx | 38 ++++++++++----- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/content/01-getting-started/02-quickstart.mdx b/content/01-getting-started/02-quickstart.mdx index 10db8bc84b..087d81096c 100644 --- a/content/01-getting-started/02-quickstart.mdx +++ b/content/01-getting-started/02-quickstart.mdx @@ -69,14 +69,14 @@ Befor you move on, installl the npm dependencies with this command: npm install ``` -## Writing your first query with Prisma Client +## Write your first query with Prisma Client The code inside `src/index.js` currently looks as follows: ```js -const { PrismaClient } = require("@prisma/client"); +const { PrismaClient } = require("@prisma/client") -const prisma = new PrismaClient(); +const prisma = new PrismaClient() async function main() { // ... you will write your Prisma Client queries here @@ -84,11 +84,11 @@ async function main() { main() .catch(e => { - throw e; + throw e }) .finally(async () => { - await prisma.disconnect(); - }); + await prisma.disconnect() + }) ```
    @@ -108,8 +108,8 @@ Inside the `main` function, add the folowing query to read all `User` records fr ```js async function main() { - const allUserss = await prisma.user.findMany(); - console.log(allUsers); + const allUserss = await prisma.user.findMany() + console.log(allUsers) } ``` @@ -125,7 +125,7 @@ This should print following result to output: [ { id: 1, email: "sarah@prisma.io", name: "Sarah" }, { id: 2, email: "maria@prisma.io", name: "Maria" }, -]; +] ``` One of the main features of Prisma Client is the ease for working with relations. You can retrieve the `posts` of each user by using the `include` option. Adjust your code to look as follows: @@ -134,9 +134,9 @@ One of the main features of Prisma Client is the ease for working with relations async function main() { const allUsers = await prisma.user.findMany({ include: { posts: true }, - }); + }) // use `console.dir` to print nested objects - console.dir(allUsers, { depth: null }); + console.dir(allUsers, { depth: null }) } ``` @@ -164,7 +164,7 @@ Each object inside `allUsers` now includes a `posts` field which represents the Congratulations, you just wrote your first query with Prisma Client 🎉 -## Write data in the database +## Write data into the database The `findMany` query you used in the previous section only _reads_ data from the database. In this section, you'll learn how to write a query to _write_ new records into the `Post` and `User` tables. @@ -179,13 +179,13 @@ async function main() { connect: { email: "sarah@prisma.io" }, }, }, - }); - console.log(post); + }) + console.log(post) const allUsers = await prisma.user.findMany({ include: { posts: true }, - }); - console.dir(allUsers, { depth: null }); + }) + console.dir(allUsers, { depth: null }) } ``` @@ -242,8 +242,8 @@ async function main() { const post = await prisma.post.update({ where: { id: 2 }, data: { published: true }, - }); - console.log(post); + }) + console.log(post) } ``` @@ -301,7 +301,7 @@ const filteredPosts = await prisma.post.findMany({ }, ], }, -}); +}) ``` **Create a new `User` and a new `Post` record in the same query** @@ -317,7 +317,7 @@ const user = await prisma.user.create({ }, }, }, -}); +}) ``` **Use the fluent relations API to retrieve the `Post` records of a `User`** @@ -327,7 +327,7 @@ const posts = await prisma.user .findOne({ where: { email: "sarah@prisma.io" }, }) - .posts(); + .posts() ``` **Delete a `User` record** @@ -335,7 +335,7 @@ const posts = await prisma.user ```js const deletedUser = await prisma.user.delete({ where: { email: "sarah@prisma.io" }, -}); +}) ``` @@ -362,7 +362,7 @@ sqlite3 ./prisma/dev.db \ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "bio" TEXT, "user" TEXT NOT NULL UNIQUE REFERENCES "User"(id) ON DELETE SET NULL -);' +)' ``` Then, introspect your database with this command from the Prisma CLI: diff --git a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx index 3a03f8293b..af4b31f6c9 100644 --- a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx +++ b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx @@ -102,7 +102,7 @@ When running PostgreSQL locally, your user and password as well as the database DATABASE_URL="postgresql://janedoe:janedoe@localhost:5432/janedoe?schema=hello-prisma" ``` -## Create database tables +## Create database tables with SQL In this guide, you'll use plain SQL to create the tables in your database. Create a new file called `schema.sql` and add the following contents to it: @@ -189,7 +189,7 @@ Great, you now created three tables in your database -## Introspect your database +## Introspect your database with Prisma As a next step, you will introspect your database. The result of the introspection will be a [data model]() inside your Prisma schema. @@ -261,7 +261,7 @@ Because the `@prisma/client` node module actually is customized to your project, ![](https://i.imgur.com/83djlkl.png) -## Writing your first query with Prisma Client +## Write your first query with Prisma Client Now that you generated your Prisma Client library, you can start writing queries to read and write data in your database. For the purpose of this guide, you'll use a plain Node.js script to explore some basic features of Prisma Client. @@ -314,7 +314,7 @@ This should print an empty arrays because there are not `User` records in the da [] ``` -## Write data in the database +## Write data into the database The `findMany` query you used in the previous section only _reads_ data from the database (although it was still empty). In this section, you'll learn how to write a query to _write_ new records into the `Post` and `User` tables. @@ -328,21 +328,27 @@ async function main() { name: "Alice", email: "alice@prisma.io", author: { - create: { title: "Prisma makes databases easy" }, + create: { title: "Hello World" }, }, - }, + profile: { + create: { bio: "I like turtles" } + } + } }) const allUsers = await prisma.user.findMany({ - include: { posts: true }, + include: { + posts: true, + profile: true + }, }) console.dir(allUsers, { depth: null }) } ``` -This code creates a new `User` record together with a new `Post` record using a [nested write]() query. The two are connected via their `author` and `posts` [relation fields]() respectively. +This code creates a new `User` record together with new `Post` and `Profile` records using a [nested write]() query. The `User` record is connected to the two other ones via the `Post.author` ↔ `User.posts` and `Profile.user` ↔ `User.profile` [relation fields]() respectively. -Notice that you're passing the [`include`]() option to `findMany` which tells Prisma Client to include the `posts` relation on the returned `User` objects. +Notice that you're passing the [`include`]() option to `findMany` which tells Prisma Client to include the `posts` and `profile` relations on the returned `User` objects. Run the code with this command: @@ -366,7 +372,10 @@ The output should look similar to this: published: false, title: 'Hello World' } - ] + ], + profile: { + bio: 'I like turtles' + } } ] ``` @@ -385,8 +394,13 @@ The query added new records to the `User` and the `Post` tables: | :----- | :------------------------- | :-------------- | :---------- | :------------ | :--------- | | `1` | `2020-03-21T16:45:01.246Z` | `"Hello World"` | `null` | `false` | `1` | +**Profile** + +| **id** | **bio** | **user** | +| :----- | :------------------ | :-------- | +| `1` | `"I like turtles"` | `1` | -> **Note**: The number in the `author` column references the `id` column of the `User` table: the `1` in the `author` column refers to the `User` record with an `id` value of `1`. +> **Note**: The numbers in the `author` column on `Post` and `user` column on `Profile` reference the `id` column of the `User` table: the `id` value `1` column therefore refers to the first (and only) `User` record in the database. Before moving on to the next section, you'll "publish" the `Post` record you just created using an `update` query. Adjust the `main` function as follows: @@ -417,7 +431,7 @@ You will see the following output: } ``` -The `Post` record with an `id` of `2` now got updated in the database: +The `Post` record with an `id` of `1` now got updated in the database: **Post** From aa436bb1f2510579cadfde6d52fe7da2836ebe72 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sat, 21 Mar 2020 19:39:42 +0100 Subject: [PATCH 19/33] add setup guides --- content/01-getting-started/02-quickstart.mdx | 12 +- .../02-start-from-scratch-sql-migrations.mdx | 334 ++++++------------ .../01-what-is-the-prisma-schema.mdx | 0 .../02-data-sources.mdx | 0 .../03-generators.mdx | 0 .../04-data-model.mdx | 0 .../05-models.mdx | 0 .../06-relations.mdx | 0 .../{01-schema => 01-prisma-schema}/index.mdx | 2 +- .../01-postgresql.mdx | 7 + .../02-mysql.mdx | 7 + .../03-sqlite.mdx | 7 + .../08-renaming-tables-and-columns/index.mdx | 4 + 13 files changed, 141 insertions(+), 232 deletions(-) rename content/03-reference/01-tools-and-interfaces/{01-schema => 01-prisma-schema}/01-what-is-the-prisma-schema.mdx (100%) rename content/03-reference/01-tools-and-interfaces/{01-schema => 01-prisma-schema}/02-data-sources.mdx (100%) rename content/03-reference/01-tools-and-interfaces/{01-schema => 01-prisma-schema}/03-generators.mdx (100%) rename content/03-reference/01-tools-and-interfaces/{01-schema => 01-prisma-schema}/04-data-model.mdx (100%) rename content/03-reference/01-tools-and-interfaces/{01-schema => 01-prisma-schema}/05-models.mdx (100%) rename content/03-reference/01-tools-and-interfaces/{01-schema => 01-prisma-schema}/06-relations.mdx (100%) rename content/03-reference/01-tools-and-interfaces/{01-schema => 01-prisma-schema}/index.mdx (72%) create mode 100644 content/04-guides/01-database-workflows/08-renaming-tables-and-columns/01-postgresql.mdx create mode 100644 content/04-guides/01-database-workflows/08-renaming-tables-and-columns/02-mysql.mdx create mode 100644 content/04-guides/01-database-workflows/08-renaming-tables-and-columns/03-sqlite.mdx create mode 100644 content/04-guides/01-database-workflows/08-renaming-tables-and-columns/index.mdx diff --git a/content/01-getting-started/02-quickstart.mdx b/content/01-getting-started/02-quickstart.mdx index 087d81096c..3b902fa110 100644 --- a/content/01-getting-started/02-quickstart.mdx +++ b/content/01-getting-started/02-quickstart.mdx @@ -293,12 +293,8 @@ Here are a few suggestions for a number of more queries you can send with Prisma const filteredPosts = await prisma.post.findMany({ where: { OR: [ - { - title: { contains: "prisma" }, - }, - { - content: { contains: "prisma" }, - }, + { title: { contains: "prisma" } }, + { content: { contains: "prisma" } }, ], }, }) @@ -312,9 +308,7 @@ const user = await prisma.user.create({ name: "Nancy", email: "nancy@prisma.io", posts: { - create: { - title: "Join us for Prisma Day 2020", - }, + create: { title: "Join us for Prisma Day 2020" }, }, }, }) diff --git a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx index af4b31f6c9..223a99b747 100644 --- a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx +++ b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx @@ -6,7 +6,7 @@ metaDescription: "" ## Overview -This page explains walks you through the process of setting up Prisma from scratch with your own database. It uses plain SQL to create tables in your database. +This page walks you through the process of setting up Prisma from scratch with your own database. It uses plain SQL to create tables in your database. ## Prerequisites @@ -80,7 +80,7 @@ The format of the connection URL for your database typically depends on the data postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=SCHEMA ``` -Here's a short summary of each component: +Here's a short explanation of each component: - `USER`: The name of your database user - `PASSWORD`: The password your database user @@ -239,7 +239,23 @@ model User { Prisma's data model is a declarative representation of your database schema and serves as foundation for the generated Prisma Client library. Your Prisma Client instance will expose queries that are _tailored_ to these models. -Right now, there's one +![](https://imgur.com/EYC3RIK.png) + +Right now, there's one minor "issue" with the data model. The `post` relation field on `User` is slightly misnamed after the introspection, since it's actually a [list]() of posts – a better name therefore would be `posts`. This is relevant for the generated Prisma Client API where using `posts` will feel more natural than `post`. + +To make this change, manually rename the `post` field to `posts`: + +```prisma +model User { + id Int @default(autoincrement()) @id + name String? + email String @unique + posts Post[] + profile Profile? +} +``` + +> **Note**: The `posts` field is [virtual]() so you can rename it in your Prisma schema without using [`@map`](). Learn more about [configuring your Prisma Client API](). ## Install and generate Prisma Client @@ -257,6 +273,8 @@ npx prisma generate This commands reads your Prisma schema and generates your Prisma Client library into `node_modules/@prisma/client`. +![](https://imgur.com/0kmSv6l.png) + Because the `@prisma/client` node module actually is customized to your project, it is sometimes referred to as a "smart node module": ![](https://i.imgur.com/83djlkl.png) @@ -441,237 +459,109 @@ The `Post` record with an `id` of `1` now got updated in the database: Fantastic, you just wrote new data into your database for the first time using Prisma Client 🚀 + ## Next steps +### Continue exploring the Prisma Client API + +You can send a variety of different queries with the Prisma Client API. Check out the [API reference]() and use your existing PostgreSQL-based setup from this guide to try them out. + +**Tip**: You can use your editor's auto-completion feature to learn about the different API calls and the arguments it takes. Auto-completion is commonly invoked by hitting CTRL+SPACE on your keyboard. + +
    Expand for more Prisma Client API examples + +Here are a few suggestions for a number of more queries you can send with Prisma Client: + +**Filter all `Post` records that contain `"hello"`** + +```js +const filteredPosts = await prisma.post.findMany({ + where: { + OR: [ + { title: { contains: "hello" }, + { content: { contains: "hello" }, + ], + }, +}) +``` + +**Create a new `Post` record and connect it to an existing `User` record** + +```js +const post = await prisma.post.create({ + data: { + title: "Join us for Prisma Day 2020", + posts: { + connect: { email: "alice@prisma.io" }, + }, + }, +}) +``` +**Use the fluent relations API to retrieve the `Post` records of a `User` by traversing the relations** +```js +const posts = await prisma.profile + .findOne({ + where: { id: 1 }, + }) + .user() + .posts() +``` +**Delete a `User` record** +```js +const deletedUser = await prisma.user.delete({ + where: { email: "sarah@prisma.io" }, +}) +``` +
    +### Explore the data in Prisma Studio (experimental) +Prisma Studio is a visual editor for the data in your database. You can use it by running the following command: + +``` +npx prisma studio --experimental +``` + +### Change the database schema (e.g. add more tables) + +To evolve the app, you need to follow the same flow of the tutorial: + +1. Manually adjust your database schema using SQL +1. Re-introspect your database +1. Re-generate Prisma Client + +![](https://imgur.com/8Tp9jRL.png) + +### Try a Prisma example + +The [`prisma-examples`]() repository contains a number of ready-to-run examples: + +#### TypeScript + +| Demo | Stack | Description | +| :----------------------------------------------------------------------------------------------------------------- | :----------- | --------------------------------------------------------------------------------------------------- | +| [`rest-nextjs`](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/rest-nextjs) | Fullstack | Simple [Next.js](https://nextjs.org/) app (React) with a REST API | +| [`graphql-nextjs`](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/graphql-nextjs) | Fullstack | Simple [Next.js](https://nextjs.org/) app (React) with a GraphQL API | +| [`graphql-apollo-server`](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/graphql-apollo-server) | Backend only | Simple GraphQL server based on [`apollo-server`](https://www.apollographql.com/docs/apollo-server/) | +| [`rest-express`](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/rest-express) | Backend only | Simple REST API with Express.JS | +| [`grpc`](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/grpc) | Backend only | Simple gRPC API | + +#### JavaScript (Node.js) + +| Demo | Stack | Description | +| :----------------------------------------------------------------------------------------------------------------- | :----------- | :-------------------------------------------------------------------------------------------------- | +| [`rest-nextjs`](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/rest-nextjs) | Fullstack | Simple [Next.js](https://nextjs.org/) app (React) with a REST API | +| [`graphql-apollo-server`](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/graphql-apollo-server) | Backend only | Simple GraphQL server based on [`apollo-server`](https://www.apollographql.com/docs/apollo-server/) | +| [`rest-express`](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/rest-express) | Backend only | Simple REST API with Express.JS | +| [`grpc`](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/grpc) | Backend only | Simple gRPC API | ---- ---- - diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/01-what-is-the-prisma-schema.mdx similarity index 100% rename from content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx rename to content/03-reference/01-tools-and-interfaces/01-prisma-schema/01-what-is-the-prisma-schema.mdx diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/02-data-sources.mdx similarity index 100% rename from content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx rename to content/03-reference/01-tools-and-interfaces/01-prisma-schema/02-data-sources.mdx diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/03-generators.mdx similarity index 100% rename from content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx rename to content/03-reference/01-tools-and-interfaces/01-prisma-schema/03-generators.mdx diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/04-data-model.mdx similarity index 100% rename from content/03-reference/01-tools-and-interfaces/01-schema/04-data-model.mdx rename to content/03-reference/01-tools-and-interfaces/01-prisma-schema/04-data-model.mdx diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/05-models.mdx similarity index 100% rename from content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx rename to content/03-reference/01-tools-and-interfaces/01-prisma-schema/05-models.mdx diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx similarity index 100% rename from content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx rename to content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/index.mdx similarity index 72% rename from content/03-reference/01-tools-and-interfaces/01-schema/index.mdx rename to content/03-reference/01-tools-and-interfaces/01-prisma-schema/index.mdx index b0faddb77a..a57f6ac356 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/index.mdx @@ -1,5 +1,5 @@ --- -title: "Schema" +title: "Prisma schema" metaTitle: "" metaDescription: "" experimental: true diff --git a/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/01-postgresql.mdx b/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/01-postgresql.mdx new file mode 100644 index 0000000000..6b2faa64cf --- /dev/null +++ b/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/01-postgresql.mdx @@ -0,0 +1,7 @@ +--- +title: "Renaming tables and columns (PostgreSQL)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/02-mysql.mdx b/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/02-mysql.mdx new file mode 100644 index 0000000000..fc55fe2eea --- /dev/null +++ b/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/02-mysql.mdx @@ -0,0 +1,7 @@ +--- +title: "Renaming tables and columns (MySQL)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 diff --git a/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/03-sqlite.mdx b/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/03-sqlite.mdx new file mode 100644 index 0000000000..64b8c00166 --- /dev/null +++ b/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/03-sqlite.mdx @@ -0,0 +1,7 @@ +--- +title: "Renaming tables and columns (SQLite)" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 diff --git a/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/index.mdx b/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/index.mdx new file mode 100644 index 0000000000..f0d25c081a --- /dev/null +++ b/content/04-guides/01-database-workflows/08-renaming-tables-and-columns/index.mdx @@ -0,0 +1,4 @@ +--- +title: "Data validation" +metaTitle: "" +--- From 21b71c67adfa7ec83c1859787d841c2ed16f288e Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sat, 21 Mar 2020 20:15:47 +0100 Subject: [PATCH 20/33] continue docs --- .../01-add-to-an-existing-project.mdx | 534 +++++++++++++++++- .../02-start-from-scratch-sql-migrations.mdx | 8 +- 2 files changed, 538 insertions(+), 4 deletions(-) diff --git a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx index 32e158faca..5e52d2d5df 100644 --- a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx +++ b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx @@ -6,6 +6,538 @@ metaDescription: "" ## Overview +This page walks you through the process of adding Prisma to a Node.js project with an existing database. + +## Prerequisites + +In order to successfully complete this guide, you need: + +- an existing Node.js (version 10 or higher) project with a `package.json` +- [Node.js]() installed on your machine +- a [PostgreSQL]() database server running and a database with at least one table + +Make sure your have your database [connection URL]() (includes your authentication credentials) at hand! + +If you don't have a database server running and only want to explore Prisma, check out the [Quickstart](). + +## Setup Prisma + +As a first step, navigate into it your project direcctory that contains the `package.json`. + +Next, add the Prisma CLI as a development dependency in your project: + +``` +npm install @prisma/cli --save-dev +``` + +You can now invoke the Prisma CLI by prefixing it with `npx`: + +``` +npx prisma +``` + +Next, set up your Prisma project by creating your [Prisma schema]() file with the following command: + +``` +npx prisma init +``` + +This command created a new directory called `prisma` with the following contents: + +- `schema.prisma`: The Prisma schema with your database connection and the Prisma Client generator +- `.env`: A [dotenv]() file for defining environment variables (used for your database connection) + +## Connect your database + +To connect your database, you need to set the `url` field of the `datasource` block in your Prisma schema to your database [connection URL](): + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} +``` + +In this case, the `url` is [set via an environment variable]() which is defined in `prisma/.env`: + +``` +DATABASE_URL="postgresql://johndoe:johndoe@localhost:5432/mydb?schema=public" +``` + +You now need to adjust the connection URL to point to your own database. + +The format of the connection URL for your database typically depends on the database you use. For PostgreSQL, it looks as follows (the parts spelled all-uppercased are placeholders for your specific connection details): + +``` +postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=SCHEMA +``` + +Here's a short explanation of each component: + +- `USER`: The name of your database user +- `PASSWORD`: The password your database user +- `PORT`: The port where your database server is running (typically `5432` for PostgreSQL) +- `DATABASE`: The name of the [database]() +- `SCHEMA`: The name of the [schema]() inside the database + +If you're unsure what to provide for the `schema` parameter for a PostgreSQL connection URL, you can probably omit it. In that case, the default schema name `public` will be used. + +As an example, for a PostgreSQL database hosted on Heroku, the [connection string](./core/connectors/postgresql.md#connection-string) might look similar to this: + +``` +DATABASE_URL="postgresql://opnmyfngbknppm:XXX@ec2-46-137-91-216.eu-west-1.compute.amazonaws.com:5432/d50rgmkqi2ipus?schema=hello-prisma" +``` + +When running PostgreSQL locally, your user and password as well as the database name typically correspond to the current _user_ of your OS, e.g. assuming the user is called `janedoe`: + +``` +DATABASE_URL="postgresql://janedoe:janedoe@localhost:5432/janedoe?schema=hello-prisma" +``` + +## Introspect your database with Prisma + +For the purpose of this guide, we'll use a demo SQL schemas with three tables: + +```sql copy +CREATE TABLE "public"."User" ( + id SERIAL PRIMARY KEY NOT NULL, + name VARCHAR(255), + email VARCHAR(255) UNIQUE NOT NULL +); + +CREATE TABLE "public"."Post" ( + id SERIAL PRIMARY KEY NOT NULL, + title VARCHAR(255) NOT NULL, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + content TEXT, + published BOOLEAN NOT NULL DEFAULT false, + author INTEGER NOT NULL, + FOREIGN KEY (author) REFERENCES "public"."User"(id) +); + +CREATE TABLE "public"."Profile" ( + id SERIAL PRIMARY KEY NOT NULL, + bio TEXT, + "user" INTEGER UNIQUE NOT NULL, + FOREIGN KEY ("user") REFERENCES "public"."User"(id) +); +``` + +> **Note**: Some fields are written in double-quotes to ensure PostgreSQL uses proper casing. If no double-quotes are used, PostgreSQL would just read everything as _lowercase_ characters. + +
    Expand for a graphical overview of the tables + +**User** + +| Column name | Type | Primary key | Foreign key | Required | Default | +| :---------- | :------------- | :---------- | :---------- | :------- | :----------------- | +| `id` | `SERIAL` | **✔️** | No | No | _autoincrementing_ | +| `name` | `VARCHAR(255)` | No | No | No | - | +| `email` | `VARCHAR(255)` | No | No | **✔️** | - | + +**Post** + +| Column name | Type | Primary key | Foreign key | Required | Default | +| :---------- | :------------- | :---------- | :---------- | :------- | :----------------- | +| `id` | `SERIAL` | **✔️** | No | No | _autoincrementing_ | +| `createdAt` | `TIMESTAMP` | No | No | **✔️** | `now()` | +| `title` | `VARCHAR(255)` | No | No | **✔️** | - | +| `content` | `TEXT` | No | No | No | - | +| `published` | `BOOLEAN` | No | No | **✔️** | `false` | +| `author` | `INTEGER` | No | **✔️** | **✔️** | `false` | + +**Profile** + +| Column name | Type | Primary key | Foreign key | Required | Default | +| :---------- | :-------- | :---------- | :---------- | :------- | :----------------- | +| `id` | `SERIAL` | **✔️** | No | No | _autoincrementing_ | +| `bio` | `TEXT` | No | No | **✔️** | - | +| `user` | `INTEGER` | No | **✔️** | **✔️** | `false` | + +
    + +As a next step, you will introspect your database. The result of the introspection will be a [data model]() inside your Prisma schema. + +Run the following command to introspect your database: + +``` +npx prisma introspect +``` + +This commands reads the `DATABASE_URL` environment variable that's defined in `.env` and connects to your database. Once the connection is established, it introspects the database (i.e. it _reads the database schema_). It then translates the database schema from SQL into a Prisma data model. + +After the introspection has completed, your Prisma schema file was updated: + +![](https://imgur.com/EYC3RIK.png) + + +It now looks similar to this (note that the fields on the models have been reordered for better readability): + +```prisma +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model Post { + id Int @default(autoincrement()) @id + createdAt DateTime @default(now()) + title String + content String? + published Boolean @default(false) + author User @relation(references: [id]) +} + +model Profile { + id Int @default(autoincrement()) @id + bio String? + user User @relation(references: [id]) +} + +model User { + id Int @default(autoincrement()) @id + name String? + email String @unique + post Post[] + profile Profile? +} +``` + +Prisma's data model is a declarative representation of your database schema and serves as foundation for the generated Prisma Client library. Your Prisma Client instance will expose queries that are _tailored_ to these models. + +Right now, there's one minor "issue" with the data model. The `post` relation field on `User` is slightly misnamed after the introspection, since it's actually a [list]() of posts – a better name therefore would be `posts`. This is relevant for the generated Prisma Client API where using `posts` will feel more natural than `post`. + +To make this change, manually rename the `post` field to `posts`: + +```prisma +model User { + id Int @default(autoincrement()) @id + name String? + email String @unique + posts Post[] + profile Profile? +} +``` + +> **Note**: The `posts` field is [virtual]() so you can rename it in your Prisma schema without using [`@map`](). Learn more about [configuring your Prisma Client API](). + +## Install and generate Prisma Client + +To get started with Prisma Client, you need to install it as a node module: + +``` +npm install @prisma/client +``` + +Notice that the [`@prisma/client` node module]() is a bit different from "conventional" node modules (e.g. a library like [`lodash`]()). When installing the module with `npm install @prisma/client`, npm only downloads an empty package into the `node_modules/@prisma/client` directory. The package is then "filled" with the actual library with the following command of the Prisma CLI: + +``` +npx prisma generate +``` + +This commands reads your Prisma schema and generates your Prisma Client library into `node_modules/@prisma/client`. + +![](https://imgur.com/0kmSv6l.png) + +Because the `@prisma/client` node module actually is customized to your project, it is sometimes referred to as a "smart node module": + +![](https://i.imgur.com/83djlkl.png) + +## Write your first query with Prisma Client + +Now that you generated your Prisma Client library, you can start writing queries to read and write data in your database. For the purpose of this guide, you'll use a plain Node.js script to explore some basic features of Prisma Client. + +Create a new file called `index.js` and add the following code to it: + +```js +const { PrismaClient } = require("@prisma/client") + +const prisma = new PrismaClient() + +async function main() { + // ... you will write your Prisma Client queries here +} + +main() + .catch(e => { + throw e + }) + .finally(async () => { + await prisma.disconnect() + }) +``` + +Here's a quick overview of the different parts of the code snippet: + +1. Import the `PrismaClient` constructor from the `@prisma/client` node module +1. Instantiate `PrismaClient` +1. Define an `async` function called `main` to send queries to the database +1. Call the `main` function +1. Close the database connections when the script terminates + +Inside the `main` function, add the folowing query to read all `User` records from the database and print the result: + +```js +async function main() { + const allUsers = await prisma.user.findMany() + console.log(allUsers) +} +``` + +Now run the code with this command: + +``` +node index.js +``` + +This should print an empty arrays because there are not `User` records in the databse yet: + +```js +[] +``` + +## Write data into the database + +The `findMany` query you used in the previous section only _reads_ data from the database (although it was still empty). In this section, you'll learn how to write a query to _write_ new records into the `Post` and `User` tables. + +Adjust the `main` function to send a `create` query to the database: + +```js +async function main() { + + await prisma.user.create({ + data: { + name: "Alice", + email: "alice@prisma.io", + author: { + create: { title: "Hello World" }, + }, + profile: { + create: { bio: "I like turtles" } + } + } + }) + + const allUsers = await prisma.user.findMany({ + include: { + posts: true, + profile: true + }, + }) + console.dir(allUsers, { depth: null }) +} +``` + +This code creates a new `User` record together with new `Post` and `Profile` records using a [nested write]() query. The `User` record is connected to the two other ones via the `Post.author` ↔ `User.posts` and `Profile.user` ↔ `User.profile` [relation fields]() respectively. + +Notice that you're passing the [`include`]() option to `findMany` which tells Prisma Client to include the `posts` and `profile` relations on the returned `User` objects. + +Run the code with this command: + +``` +node index.js +``` + +The output should look similar to this: + +```js +[ + { + email: 'alice@prisma.io', + id: 1, + name: 'Alice', + posts: [ + { + content: null, + createdAt: 2020-03-21T16:45:01.246Z, + id: 1, + published: false, + title: 'Hello World' + } + ], + profile: { + bio: 'I like turtles' + } + } +] +``` + +The query added new records to the `User` and the `Post` tables: + +**User** + +| **id** | **email** | **name** | +| :----- | :------------------ | :-------- | +| `1` | `"alice@prisma.io"` | `"Alice"` | + +**Post** + +| **id** | **createdAt** | **title** | **content** | **published** | **author** | +| :----- | :------------------------- | :-------------- | :---------- | :------------ | :--------- | +| `1` | `2020-03-21T16:45:01.246Z` | `"Hello World"` | `null` | `false` | `1` | + +**Profile** + +| **id** | **bio** | **user** | +| :----- | :------------------ | :-------- | +| `1` | `"I like turtles"` | `1` | + +> **Note**: The numbers in the `author` column on `Post` and `user` column on `Profile` reference the `id` column of the `User` table: the `id` value `1` column therefore refers to the first (and only) `User` record in the database. + +Before moving on to the next section, you'll "publish" the `Post` record you just created using an `update` query. Adjust the `main` function as follows: + +```js +async function main() { + const post = await prisma.post.update({ + where: { id: 1 }, + data: { published: true }, + }) + console.log(post) +} +``` + +Now run the code using the same command as before: + +``` +node index.js +``` + +You will see the following output: + +```js +{ + id: 1, + title: 'Hello World', + content: null, + published: true +} +``` + +The `Post` record with an `id` of `1` now got updated in the database: + +**Post** + +| **id** | **title** | **content** | **published** | **author** | +| :----- | :------------------------------ | :---------- | :------------ | :--------- | +| `1` | `"Hello World"` | `null` | `true` | `1` | + +Fantastic, you just wrote new data into your database for the first time using Prisma Client 🚀 + + +## Next steps + +### Continue exploring the Prisma Client API + +You can send a variety of different queries with the Prisma Client API. Check out the [API reference]() and use your existing PostgreSQL-based setup from this guide to try them out. + +**Tip**: You can use your editor's auto-completion feature to learn about the different API calls and the arguments it takes. Auto-completion is commonly invoked by hitting CTRL+SPACE on your keyboard. + +
    Expand for more Prisma Client API examples + +Here are a few suggestions for a number of more queries you can send with Prisma Client: + +**Filter all `Post` records that contain `"hello"`** + +```js +const filteredPosts = await prisma.post.findMany({ + where: { + OR: [ + { title: { contains: "hello" }, + { content: { contains: "hello" }, + ], + }, +}) +``` + +**Create a new `Post` record and connect it to an existing `User` record** + +```js +const post = await prisma.post.create({ + data: { + title: "Join us for Prisma Day 2020", + posts: { + connect: { email: "alice@prisma.io" }, + }, + }, +}) +``` + +**Use the fluent relations API to retrieve the `Post` records of a `User` by traversing the relations** + +```js +const posts = await prisma.profile + .findOne({ + where: { id: 1 }, + }) + .user() + .posts() +``` + +**Delete a `User` record** + +```js +const deletedUser = await prisma.user.delete({ + where: { email: "sarah@prisma.io" }, +}) +``` + +
    + +### Explore the data in Prisma Studio (experimental) + +Prisma Studio is a visual editor for the data in your database. You can use it by running the following command: + +``` +npx prisma studio --experimental +``` + +### Change the database schema (e.g. add more tables) + +To evolve the app, you need to follow the same flow of the tutorial: + +1. Manually adjust your database schema using SQL +1. Re-introspect your database +1. Re-generate Prisma Client + +![](https://imgur.com/8Tp9jRL.png) + +### Try a Prisma example + +The [`prisma-examples`]() repository contains a number of ready-to-run examples: + +#### TypeScript + +| Demo | Stack | Description | +| :----------------------------------------------------------------------------------------------------------------- | :----------- | --------------------------------------------------------------------------------------------------- | +| [`rest-nextjs`](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/rest-nextjs) | Fullstack | Simple [Next.js](https://nextjs.org/) app (React) with a REST API | +| [`graphql-nextjs`](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/graphql-nextjs) | Fullstack | Simple [Next.js](https://nextjs.org/) app (React) with a GraphQL API | +| [`graphql-apollo-server`](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/graphql-apollo-server) | Backend only | Simple GraphQL server based on [`apollo-server`](https://www.apollographql.com/docs/apollo-server/) | +| [`rest-express`](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/rest-express) | Backend only | Simple REST API with Express.JS | +| [`grpc`](https://github.com/prisma/prisma-examples/tree/prisma2/typescript/grpc) | Backend only | Simple gRPC API | + +#### JavaScript (Node.js) + +| Demo | Stack | Description | +| :----------------------------------------------------------------------------------------------------------------- | :----------- | :-------------------------------------------------------------------------------------------------- | +| [`rest-nextjs`](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/rest-nextjs) | Fullstack | Simple [Next.js](https://nextjs.org/) app (React) with a REST API | +| [`graphql-apollo-server`](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/graphql-apollo-server) | Backend only | Simple GraphQL server based on [`apollo-server`](https://www.apollographql.com/docs/apollo-server/) | +| [`rest-express`](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/rest-express) | Backend only | Simple REST API with Express.JS | +| [`grpc`](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/grpc) | Backend only | Simple gRPC API | + + + + + + + + + diff --git a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx index 223a99b747..848a26acd8 100644 --- a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx +++ b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx @@ -201,7 +201,11 @@ npx prisma introspect This commands reads the `DATABASE_URL` environment variable that's defined in `.env` and connects to your database. Once the connection is established, it introspects the database (i.e. it _reads the database schema_). It then translates the database schema from SQL into a Prisma data model. -After the introspection has completed, your Prisma schema file was updated and now looks as follows (note that the fields on the models have been reordered for better readability): +After the introspection has completed, your Prisma schema file was updated: + +![](https://imgur.com/EYC3RIK.png) + +It now looks as follows (note that the fields on the models have been reordered for better readability): ```prisma generator client { @@ -239,8 +243,6 @@ model User { Prisma's data model is a declarative representation of your database schema and serves as foundation for the generated Prisma Client library. Your Prisma Client instance will expose queries that are _tailored_ to these models. -![](https://imgur.com/EYC3RIK.png) - Right now, there's one minor "issue" with the data model. The `post` relation field on `User` is slightly misnamed after the introspection, since it's actually a [list]() of posts – a better name therefore would be `posts`. This is relevant for the generated Prisma Client API where using `posts` will feel more natural than `post`. To make this change, manually rename the `post` field to `posts`: From 25be24f986476e96d8fd4debf8c6b9f32f93a56f Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sat, 21 Mar 2020 20:38:46 +0100 Subject: [PATCH 21/33] continue docs --- .../01-add-to-an-existing-project.mdx | 114 ++---------------- 1 file changed, 9 insertions(+), 105 deletions(-) diff --git a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx index 5e52d2d5df..2154719de6 100644 --- a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx +++ b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx @@ -249,7 +249,9 @@ Because the `@prisma/client` node module actually is customized to your project, ## Write your first query with Prisma Client -Now that you generated your Prisma Client library, you can start writing queries to read and write data in your database. For the purpose of this guide, you'll use a plain Node.js script to explore some basic features of Prisma Client. +Now that you generated your Prisma Client library, you can start writing queries to read and write data in your database. So, now would be the time to start integrating Prisma Client in your application. For example, if you're building a REST API, you can use Prisma Client in your route handlers to read and write data in the database based on incoming HTTP requests. If you're building a GraphQL API, you can use Prisma Client in your resolvers to read and write data in the database based on incoming queries and mutations. + +For the purpose of this guide however, you'll just create a plain Node.js script to learn how to send queries to your database using Prisma Client. Once you have an understanding of how the API works, you can start integrating it into your actual application code (e.g. REST route handlers or GraphQL resolvers). Create a new file called `index.js` and add the following code to it: @@ -279,6 +281,10 @@ Here's a quick overview of the different parts of the code snippet: 1. Call the `main` function 1. Close the database connections when the script terminates +Depending on what your models look like, the Prisma Client API will look different as well. For example, if you have a `User` model, your `PrismaClient` instance exposes a property called `user` on which you can call [CRUD]() methods like `findMany`, `create` or `update`. The property named after the model, but the first letter is lowercased (so for the `Post` model the property is called `post`, for `Profile` it's called profile). + +The following examples are all based on the models in the Prisma schema. + Inside the `main` function, add the folowing query to read all `User` records from the database and print the result: ```js @@ -294,15 +300,11 @@ Now run the code with this command: node index.js ``` -This should print an empty arrays because there are not `User` records in the databse yet: - -```js -[] -``` +This will print an array of `User` records as plain old JavaScript objects. ## Write data into the database -The `findMany` query you used in the previous section only _reads_ data from the database (although it was still empty). In this section, you'll learn how to write a query to _write_ new records into the `Post` and `User` tables. +The `findMany` query you used in the previous section only _reads_ data from the database. In this section, you'll learn how to write a query to _write_ new records into the `Post` and `User` tables. Adjust the `main` function to send a `create` query to the database: @@ -342,52 +344,6 @@ Run the code with this command: node index.js ``` -The output should look similar to this: - -```js -[ - { - email: 'alice@prisma.io', - id: 1, - name: 'Alice', - posts: [ - { - content: null, - createdAt: 2020-03-21T16:45:01.246Z, - id: 1, - published: false, - title: 'Hello World' - } - ], - profile: { - bio: 'I like turtles' - } - } -] -``` - -The query added new records to the `User` and the `Post` tables: - -**User** - -| **id** | **email** | **name** | -| :----- | :------------------ | :-------- | -| `1` | `"alice@prisma.io"` | `"Alice"` | - -**Post** - -| **id** | **createdAt** | **title** | **content** | **published** | **author** | -| :----- | :------------------------- | :-------------- | :---------- | :------------ | :--------- | -| `1` | `2020-03-21T16:45:01.246Z` | `"Hello World"` | `null` | `false` | `1` | - -**Profile** - -| **id** | **bio** | **user** | -| :----- | :------------------ | :-------- | -| `1` | `"I like turtles"` | `1` | - -> **Note**: The numbers in the `author` column on `Post` and `user` column on `Profile` reference the `id` column of the `User` table: the `id` value `1` column therefore refers to the first (and only) `User` record in the database. - Before moving on to the next section, you'll "publish" the `Post` record you just created using an `update` query. Adjust the `main` function as follows: ```js @@ -406,28 +362,6 @@ Now run the code using the same command as before: node index.js ``` -You will see the following output: - -```js -{ - id: 1, - title: 'Hello World', - content: null, - published: true -} -``` - -The `Post` record with an `id` of `1` now got updated in the database: - -**Post** - -| **id** | **title** | **content** | **published** | **author** | -| :----- | :------------------------------ | :---------- | :------------ | :--------- | -| `1` | `"Hello World"` | `null` | `true` | `1` | - -Fantastic, you just wrote new data into your database for the first time using Prisma Client 🚀 - - ## Next steps ### Continue exploring the Prisma Client API @@ -529,33 +463,3 @@ The [`prisma-examples`]() repository contains a number of ready-to-run examples: | [`grpc`](https://github.com/prisma/prisma-examples/tree/prisma2/javascript/grpc) | Backend only | Simple gRPC API | - - - - - - - From e411a55223fe24a22498463c54464164e361e1e5 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sun, 22 Mar 2020 07:41:34 +0100 Subject: [PATCH 22/33] continue docs --- content/01-getting-started/02-quickstart.mdx | 2 +- .../01-add-to-an-existing-project.mdx | 35 ++++++++++++++++++- .../01-prisma-schema/05-models.mdx | 8 +++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/content/01-getting-started/02-quickstart.mdx b/content/01-getting-started/02-quickstart.mdx index 3b902fa110..2ffc189c9e 100644 --- a/content/01-getting-started/02-quickstart.mdx +++ b/content/01-getting-started/02-quickstart.mdx @@ -108,7 +108,7 @@ Inside the `main` function, add the folowing query to read all `User` records fr ```js async function main() { - const allUserss = await prisma.user.findMany() + const allUsers = await prisma.user.findMany() console.log(allUsers) } ``` diff --git a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx index 2154719de6..0a6352fe7d 100644 --- a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx +++ b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx @@ -223,7 +223,40 @@ model User { } ``` -> **Note**: The `posts` field is [virtual]() so you can rename it in your Prisma schema without using [`@map`](). Learn more about [configuring your Prisma Client API](). +> **Note**: The `posts` field is [virtual]() so you can rename it in your Prisma schema without using [`@map`](). + +In this example, the database schema has followed all [naming conventions]() for Prisma models. This optimizes the ergonomics of the generated Prisma Client API. + +Sometimes though, when generated from introspection, relation fields that are named after a foreign key in the database are suffixed with `_id` (e.g. `profile_id`). This can lead to unintuitive situations in the Prisma Client API when a full `Profile` object would be referred to by a field which is called `profile_id`. Here are two example snippets that illustrate this: + +```js +const profile = await prisma.user.findOne({ + where: { id: 1 } +}).profile_id() + +const user = await prisma.user.create({ + data: { + name: "Alice", + profile_id: { bio: "I like turtles" } + } +}) +``` + +In that case, you might want to [configure your Prisma Client API]() and rename the relation field on the model using [`@map`](): + +```prisma +model Profile { + id Int @id @default(autoincrement()) + bio String + user User +} + +model User { + id Int @id @default(autoincrement()) + name String + profile Profile @map("profile_id") +} +``` ## Install and generate Prisma Client diff --git a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/05-models.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/05-models.mdx index 41bd8269c7..ced99b8c53 100644 --- a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/05-models.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/05-models.mdx @@ -109,6 +109,14 @@ Technically, a field can be named anything that adheres to this regular expressi > **Note**: There's currently a [bug](https://github.com/prisma/prisma2/issues/259) that doesn't allow for field names prepended with an underscore. The current regular expression for valid field names therefore is: `[A-Za-z][A-Za-z0-9_]*` +A note on naming [relation fields](): Sometimes when generated from introspection, relation fields that are named after a foreign key in the database are suffixed with `_id` (e.g. `user_id`). This can lead to unintuitive situations in the Prisma Client API when a full `User` object would be referred to by a field which is called `user_id`. In that case, you might want to [configure your Prisma Client API]() and rename the relation field on the model using `@map`: + +```prisma +model Profile { + user User @map("user_id") +} +``` + ### Field types #### Scalar fields vs relation fields From c629a3375e8ce3ff27b530226157b71e79cd894b Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sun, 22 Mar 2020 08:12:51 +0100 Subject: [PATCH 23/33] continue docs --- .../01-getting-started/01-examples-mdx.mdx | 57 ------------------- .../01-prisma-schema/06-relations.mdx | 2 +- content/05-more/01-introduction.mdx | 13 +++++ content/05-more/index.mdx | 5 ++ content/05-more/user-table.svg | 3 + 5 files changed, 22 insertions(+), 58 deletions(-) delete mode 100644 content/01-getting-started/01-examples-mdx.mdx create mode 100644 content/05-more/01-introduction.mdx create mode 100644 content/05-more/index.mdx create mode 100644 content/05-more/user-table.svg diff --git a/content/01-getting-started/01-examples-mdx.mdx b/content/01-getting-started/01-examples-mdx.mdx deleted file mode 100644 index f57df50b55..0000000000 --- a/content/01-getting-started/01-examples-mdx.mdx +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: "MDX examples" -metaTitle: "" -metaDescription: "" ---- - -## Paragraph - -When adding a required field to a model for which the database already stores some records, Prisma automatically sets the value for the new field (as `NULL` values are not allowed). Here is the overview of the default values that Prisma inserts for these existing records: - -## Link - -This guide is based on Prisma's [introspection](./introspection.md) - -## Table - -| Field type | Migration Value | -| ------------- | ------------- | -| `String` | `""` (empty string) | -| `Int` | `0` | -| `Float` | `0.0` | -| `Boolean` | `false` | -| `DateTime` | `1970-01-01T00:00:00Z` | -| `Json` | `{}` | -| Enum | The first value in the enum definition | -| required scalar list | `[]` | -| required to-one relation field | no default, this will error | - -## Normal code block - -```bash -npx prisma2 introspect -``` - -## Code block with copy - -```bash copy -npx prisma2 introspect -``` - -## Code block with tabs - - - -```bash copy -brew tap prisma/prisma -brew install prisma -``` - -```bash copy -npm install -g prisma -``` - - - - - diff --git a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx index 1837d1556a..33604163b8 100644 --- a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx @@ -8,7 +8,7 @@ metaDescription: "" This is an extension of the [Data model]() page which describes how to handle relations between Prisma models in the Prisma schema. -Relations are represented via foreign keys in the underlying database. However, as opposed to how relations are modelled in SQL, **Prisma always requires explicit relation fields on _both_ sides of the relation to be set on your Prisma models**. This means that one of these relation fields represents the foreign key in the underlying database, the other relation field is a [virtual relation field](). +Relations between models are represented via foreign keys in the underlying database. However, as opposed to how relations are modeled in SQL, **Prisma always requires explicit relation fields on _both_ sides of the relation to be set on your Prisma models**. This means that one of these relation fields represents the foreign key in the underlying database, the other relation field is a [virtual relation field]() (in the case of [implicit many-to-many relations]()), both relation fields are virtual. ## Example diff --git a/content/05-more/01-introduction.mdx b/content/05-more/01-introduction.mdx new file mode 100644 index 0000000000..90468a2365 --- /dev/null +++ b/content/05-more/01-introduction.mdx @@ -0,0 +1,13 @@ +--- +title: "About these docs" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +Coming 🔜 + +## The `User` and `Post` data model + +`User` and `Post` are the canonical models that are being used throughout the Prisma docs. This page gives some context on why these have been selected and how to interpret them. diff --git a/content/05-more/index.mdx b/content/05-more/index.mdx new file mode 100644 index 0000000000..bbff9f073e --- /dev/null +++ b/content/05-more/index.mdx @@ -0,0 +1,5 @@ +--- +title: "More" +metaTitle: "More" +metaDescription: "More" +--- diff --git a/content/05-more/user-table.svg b/content/05-more/user-table.svg new file mode 100644 index 0000000000..4e215fb8ef --- /dev/null +++ b/content/05-more/user-table.svg @@ -0,0 +1,3 @@ + + +UseridPKfirst_name: stringlast_name: stringemail: stringemail_confirmed: boolbirthDate: date \ No newline at end of file From 4960d8df5cbc52cefcefcb0ecda653672ef6b846 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sun, 22 Mar 2020 08:24:39 +0100 Subject: [PATCH 24/33] add more section --- .../01-prisma-schema/06-relations.mdx | 4 +- ...introduction.mdx => 01-about-the-docs.mdx} | 2 +- content/05-more/02-style-guide.mdx | 235 ++++++++++++++++++ content/05-more/03-supported-databases.mdx | 22 ++ content/05-more/04-creating-bug-reports.mdx | 126 ++++++++++ content/05-more/05-faq.mdx | 7 + content/05-more/06-limitations.mdx | 38 +++ content/05-more/07-roadmap.mdx | 117 +++++++++ 8 files changed, 549 insertions(+), 2 deletions(-) rename content/05-more/{01-introduction.mdx => 01-about-the-docs.mdx} (91%) create mode 100644 content/05-more/02-style-guide.mdx create mode 100644 content/05-more/03-supported-databases.mdx create mode 100644 content/05-more/04-creating-bug-reports.mdx create mode 100644 content/05-more/05-faq.mdx create mode 100644 content/05-more/06-limitations.mdx create mode 100644 content/05-more/07-roadmap.mdx diff --git a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx index 33604163b8..4c68d5a103 100644 --- a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx @@ -192,7 +192,9 @@ Virtual relation fields are relation fields in the Prisma schema that are not "m There are two different kinds of virtual relation fields: - 1-1 and 1-n relations: One side of the relation represents a foreign key, the other side is a virtual relation field. -- m-n (implicit): Both relation fields are virtual since neither of them directly maps to a foreign key. +- m-n (implicit): Both relation fields are virtual since neither of them directly maps to a foreign key. + +Note that the virtual relation fields in m-n-relations still have Prisma always requires both sides of a relation to be present, this means that one virtual relation field always needs to be added per relation. When [formatting the Prisma schema](), the formatter automatically inserts any missing virtual relation fields for you to save some typing work. diff --git a/content/05-more/01-introduction.mdx b/content/05-more/01-about-the-docs.mdx similarity index 91% rename from content/05-more/01-introduction.mdx rename to content/05-more/01-about-the-docs.mdx index 90468a2365..ff2ececf9f 100644 --- a/content/05-more/01-introduction.mdx +++ b/content/05-more/01-about-the-docs.mdx @@ -1,5 +1,5 @@ --- -title: "About these docs" +title: "About the docs" metaTitle: "" metaDescription: "" --- diff --git a/content/05-more/02-style-guide.mdx b/content/05-more/02-style-guide.mdx new file mode 100644 index 0000000000..7742c7406c --- /dev/null +++ b/content/05-more/02-style-guide.mdx @@ -0,0 +1,235 @@ +--- +title: "Prisma style guide" +metaTitle: "" +metaDescription: "" +--- + +## Welcome! + +Welcome! This guide contains information for writing and maintaining technical documentation for the Prisma tools. One major goal of this style guide is to ensure consistency in the Prisma documentation with respect to things like word choice, writing style, formatting and more. + +> **This style guide is heavily inspired by the [Gatsby Style Guide](https://www.gatsbyjs.org/contributing/gatsby-style-guide/).** Many sections have been bluntly copied, some others have been slightly edited and some are new and specific to the Prisma docs. + +## Word choice + +### Use "you" as the pronoun + +Any content should use the second person ("you") to provide a conversational tone. This way, the text and instructions seem to speak directly to the person reading it. Try to avoid using the first person ("I", "we", "let's", and "us"). + +Using "you" in English is also more accurate than saying "we because typically only one person is reading the tutorial or guide at a time and the person who wrote the tutorial is not actually going through it with them, so "we" would be inaccurate. You might notice that some technical documentation uses third person pronouns and nouns like "they" and "the user", which add more distance and feel colder than the conversational and warm "you" and "your". + +### Avoid words like "easy" and "just" + +Avoid using words like "easy", "just" "simple" and "basic" because if users have a hard time completing the task that is supposedly "easy," they will question their abilities. Consider using more specific descriptors; for example, when you say the phrase "deployment is easy," what do you really mean? Is it easy because it takes fewer steps than another option? If so, use the most specific descriptor possible, which in that case would be "this deployment method involves fewer steps than other options." + +For even more inclusive docs, avoid phrases that assume a reader’s experience or skill level, like "just deploy it and you’re done" or "for a refresher (referring to a completely different doc that someone may not have read)". Often, rephrasing results in stronger sentences that appeal to a wider range of contexts. + +### Use inclusive language + +When you need to refer to one or more people in third-person, be sure to use inclusive, gender-neutral language if the gender of the person is not explicitly known. Use "they/them/their" instead of "he/him/his" or "she/her/her". Avoid words like "guys" + +### Avoid emojis, slang, and metaphors + +Avoid using emojis or emoticons in the docs and idiomatic expressions / slang, or metaphors. Gatsby has a global community, and the cultural meaning of an emoji, emoticon, or slang may be different around the world. Use your best judgment! Also, emojis can render differently on different systems. + +### Define jargon + +Articles should be written with short, clear sentences, and use as little jargon as necessary. + +> Jargon: (n.) special words or expressions that are used by a particular profession or group and are difficult for others to understand: legal jargon. + +All jargon should be defined immediately in plain English. In other words, pretend like your readers have basic coding experience but not necessarily experience with PWAs and the JAMstack (see what happened there? I just used two jargon words that need to be defined); you need to define words that newcomers might have a hard time understanding. + +### Referring to other parts of the docs + +- Page +- Section + +## Writing style + +### Write concisely + +Concise writing communicates the bare minimum without redundancy. Strive to make your writing as short as possible; this practice will often lead to more accurate and specific writing. + +### Use clear hyperlinks + +Hyperlinks should contain the clearest words to indicate where the link will lead you. + +```md + +[Prisma's docs](https://www.prisma.io/docs/) + +[here](https://www.gatsbyjs.org/docs/ "Gatsby's docs") +``` + +### Indicate when something is optional + +When a paragraph or sentence offers an optional path, the beginning of the first sentence should indicate that it’s optional. For example, "if you’d like to learn more about xyz, see our reference guide" is clearer than "Go to the reference guide if you’d like to learn more about xyz." + +This method allows people who would not like to learn more about xyz to stop reading the sentence as early as possible. This method also allows people who would like to learn more about xyz to recognize the opportunity to learn quicker instead of accidentally skipping over the paragraph. + +### Abbreviate terms + +If you want to abbreviate a term in your article, write it out fully first, then put the abbreviation in parentheses. After that, you may use the abbreviation going for the rest of the article. For example, "In computer science, an abstract syntax tree (AST) is …". + +## Grammar and formatting + +### Capitalize and spell out proper nouns + +Although it can be tempting to use abbreviations like "Postgres" (instead of the official proper noun "PostgreSQL") or not worry about casing when writing "Javsccript" (instead of "JavaScript"), we're comitted to using the preferred notions of proper nouns. A few common examples are: + +- Node.js (instead of Node or Node.JS) +- JavaScript and TypeScript (instead of Javascript and Typescript or JS and TS) +- PostgreSQL (instead of Postgres or Postgresql) +- MongoDB (instead of Mongo) +- GitHub (instead of Github) +- ... + +If you're not sure about the spelling of a certain noun, the official homepage of it typically contains the proper spelling for you to look up. + +### Format titles and headers + +Page titles and headings are sentence cased, i.e., only the initial word is uppercase. Neither of them need punctuation at the end of the phrase unless a question mark is required. + +### Use tables, bullet lists and numbered lists + +Tables and lists are often the most concise way of presenting information. Use the elements whenever they feel appropriate. Here are few guidelines to help decide when to use which: + +- Use bulllet lists only when the order of the lists doesn't matter (e.g. an enumeration of the features of a database which don't have an inherent order) +- Use numbered lists only when the order of the list matters (e.g. when providing step-by-step instructions where one step builds on the previous) +- Use tables when you're enumerating things that share a number of similar properties/characteristics (e.g. the parameters for an API call which all have a "name", a "type", are required or optional and need a description) + +### Use italics and bold font + +Italics and bold fonts can be a great way to emphasize certain parts of your sentence to the reader. Use bold font more sparcely and only when you want this part to stand out from the entire paragraph (so that it's visible when a reader only "scans" the page instead of properly reading it). Use italics for words that introduce new concepts for the first time. + +### Use active voice + +Use active voice instead of passive voice. Generally, it’s a more concise and straightforward way to communicate a subject. For example: + +- (passive) The for loop in JavaScript is used by programmers to… +- (active) Programmers use the for loop in JavaScript to… + +### Make lists clear with the Oxford Comma + +Use the Oxford Comma except in titles. It is a comma used after the penultimate item in a list of three or more items, before "and" or "or" e.g. an Italian painter, sculptor, and architect. It makes things clearer. + +[Confusion can happen when you don’t use the Oxford comma.](https://img.buzzfeed.com/buzzfeed-static/static/2015-02/22/18/enhanced/webdr11/enhanced-buzz-32156-1424646300-12.jpg?downsize=715:*&output-format=auto&output-quality=auto) + +### Prefer US English + +For words that have multiple spellings, prefer the US English word over British or Canadian English. For example: + +- "color" over "colour" +- "behavior" over "behaviour" + +## Writing code snippets + +### Use inline code only when referring to "code concepts" + +TBD + +### Format code blocks and inline code + +Use the following as reference when creating and editing docs: [formatting inline code and code blocks](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code). + +### Emphasize placeholders + +Placeholders are a tricky topic in technical documentation and are one of the most common sources of confusion, especially for beginners. To strive for consistency, placeholders in the Prisma docs are: + +- spelled in all-uppercase letters +- prefixed and suffixed with two underscores +- using descriptive terms + +As an example, consider the following code block where `__DATABASE_CONNECTION_URL__` is a placeholder for the PostgreSQL connection URL: + +```prisma +datasource db { + provider = "postgresql" + url = "__DATABASE_CONNECTION_STRING__" +} +``` + +Whenever you're using a placeholder, you should make sure that you directly explain or at least link out to another resource that explains how to obtain a value for the placeholder. You should also explicitly call out that this is a placeholder that needs to get replaced with a "real value" including an example of what that real value might look like: + +```prisma +datasource db { + provider = "postgresql" + url = "postgresql://opnmyfngbknppm:XXX@ec2-46-137-91-216.eu-west-1.compute.amazonaws.com:5432/d50rgmkqi2ipus?schema=hello-prisma2" +} +``` + +### Use prettier code formatting + +TBD + +### Use expressive variable names + +TBD + +### Strive for code snippets to be "valid" + +TBD + +### Avoid too many inline comments + +TBD + +### Lists of shell commands + +When you need to provide a series of CLI commands as instructions to the reader, don't use a list unless you're providing context for each step: + +##### Bad + +- `cd path/to/server` +- `docker-compose up -d --build` +- `./node_modules/.bin/sequelize db:migrate` or `npx sequelize db:migrate` +- `./node_modules/.bin/sequelize db:seed:all` or `npx sequelize db:seed:all` + +##### Better + +```shell +cd path/to/server +docker-compose up -d --build +./node_modules/.bin/sequelize db:migrate # or `npx sequelize db:migrate` +./node_modules/.bin/sequelize db:seed:all # or `npx sequelize db:seed:all` +``` + +or + +1. Navigate into the project directory: `cd path/to/server` +1. Start Docker containers: `docker-compose up -d --build` +1. Migrate your database schema: `./node_modules/.bin/sequelize db:migrate` or `npx sequelize db:migrate` +1. Seed the database: `./node_modules/.bin/sequelize db:seed:all` or `npx sequelize db:seed:all` + +### Don't prepend CLI commands with `$` + +TBD + +### npm vs Yarn + +Always use `npm` commands instead of `yarn`. + +## Spelling + +### Hyphens + +Hyphens are used according to these [rules](https://www.grammarbook.com/punctuation/hyphens.asp). + +Sometimes there are some terms where it's not clear whether to use a hyphen or not. In order to strive for consistency, we list those terms here as a rule for using them throughout the Prisma documentation. + +#### Spell without hyphen + +- Use case +- Command line +- Type safety +- Type safe +- Auto format + +#### Spell with hyphen + +- Compile-time + +#### Spell as one word + +- Autocomplete diff --git a/content/05-more/03-supported-databases.mdx b/content/05-more/03-supported-databases.mdx new file mode 100644 index 0000000000..019609b06d --- /dev/null +++ b/content/05-more/03-supported-databases.mdx @@ -0,0 +1,22 @@ +--- +title: "Supported databases" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +Prisma 2 currently supports the following databases: + +| Database | Version | +| --- | --- | +| PostgreSQL | 9 | +| PostgreSQL | 10 | +| PostgreSQL | 11 | +| PostgreSQL | 12 | +| MySQL | 5.7 | +| MySQL | 8 | +| MariaDB | 10 | +| SQLite | 3.28.0 | + +Note that a fixed version of SQLite is shipped with every Prisma 2 release. diff --git a/content/05-more/04-creating-bug-reports.mdx b/content/05-more/04-creating-bug-reports.mdx new file mode 100644 index 0000000000..20e2f814be --- /dev/null +++ b/content/05-more/04-creating-bug-reports.mdx @@ -0,0 +1,126 @@ +--- +title: "Creating bug reports" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +You can help us improve Prisma by creating **bug reports**. When creating a bug report, it's important that you include as much information as possible about your issue. That way, it's easier to reproduce. + +Note that you can also create **feature requests** or ask a **question** via the issue templates on GitHub. + +## Ideal scenario: Share standalone repository with reproduction + +In an ideal scenario, you're able to reproduce the bug in an isolated environment and put it into a GitHub repository that you can share in your report. That way, we already have a reproduction and the problem can be tackled without further triaging. + +## Writing a bug report + +If you don't have the time to create a full reproduction of the issue, please include as much information as possible about the problem. The [bug report template]() helps you with that. + +### Include logging and debugging output + +Please make sure to include _any_ [logging](./prisma-client-js/api.md#logging) and [debugging](./prisma-client-js/api.md#debugging) output in the issue that may help to identify the problem. + +**Setting the `DEBUG` env var** + +To get additional output from Prisma, you can set `DEBUG` to `*`: + +```bash +export DEBUG="*" +``` + +**Print logs of Prisma Client** + +You can enable additional logs in Prisma Client by instantiating it with the `log` option: + +```ts +const prisma = new PrismaClient({ log: ['query', 'info', 'warn'] }) +``` + +### Include a bug description, reproduction and expected behaviour + +When describing the bug, it's helpful to include the following information: + +- A clear and concise description of what the bug is +- Steps to reproduce the bug +- A clear and concise description of what you expected to happen +- Screenshots (if applicable) + +
    Expand for an example for a hypothetical bug report + +#### Example + +**Describe the bug** + +`@unique` attribute on `email` field doesn't work on my model. I can create duplicate records with the same `email`. + +**To reproduce**: + +I have this Prisma schema (removed all unnecessary models and fields): + +```prisma +model User { + id Int @id @default(autoincrement()) + email String @unique +} +``` + +I then run `prisma generate` to generate Prisma Client. + +I then have a Node.js script that creates two `User` records with the same `email`: + +```ts +import { PrismaClient } from '@prisma/client' + +const prisma = new PrismaClient() + +// A `main` function so that we can use async/await +async function main() { + const user1 = await prisma.create({ + data: { email: 'alice@prisma.io' } + }) + const user2 = await prisma.create({ + data: { email: 'alice@prisma.io' } + }) + console.log(user1, user2) +} + +main() + .catch(e => { + throw e + }) + .finally(async () => { + await prisma.disconnect() + }) +``` + +**Expected behavior** + +I expected an exception when trying to create `user2` with the same `email` as `user1` because this violates the `@unique` constraint defined in the Prisma schema. + +
    + +### Include environment and setup information + +Please include any information about your environment and setup. Specifically it's important to include: + +- Which **operating system** you use (e.g. Mac OS, Windows, Debian, CentOS, ...) +- Which **database** you use with Prisma (PostgreSQL, MySQL or SQLite) +- Which **version of Prisma** you use (run `prisma2 -v` to see your Prisma version) +- Which **version of Prisma Node.js** you use (run `node -v` to see your Node.js version) + +Here's an example of what this could look like in your bug report: + +- OS: Mac OS Cataline 10.15.1 +- Database: PostgreSQL v11 +- Prisma version: `prisma2@2.0.0-preview024, binary version: 377df4fe30aa992f13f1ba152cf83d5770bdbc85` +- Node.js version: `v12.2.0` + +### Include relevant Prisma info (e.g. the Prisma schema, Prisma Client queries, ...) + +To help us reproduce your problem, it is helpful to include your Prisma schema in the bug report. **Please remove any database credentials before sharing your Prisma schema in a bug report**. If you're sure about which parts of the schema is causing the issue, please strip out the irrelevant parts of it and only show the parts that are related to the problem. If you're not sure, please include your entire schema. + +If you have an issue with Prisma Client, please also include which Prisma Client query is causing the issue. + + diff --git a/content/05-more/05-faq.mdx b/content/05-more/05-faq.mdx new file mode 100644 index 0000000000..3634ef9d74 --- /dev/null +++ b/content/05-more/05-faq.mdx @@ -0,0 +1,7 @@ +--- +title: "FAQ" +metaTitle: "" +metaDescription: "" +--- + +Coming 🔜 \ No newline at end of file diff --git a/content/05-more/06-limitations.mdx b/content/05-more/06-limitations.mdx new file mode 100644 index 0000000000..15a3eb4567 --- /dev/null +++ b/content/05-more/06-limitations.mdx @@ -0,0 +1,38 @@ +--- +title: "Limitations" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +This page describes features that are currently not supported by Prisma and are not planned to be supported. + +## Long-running transactionos + +Databases often offer "long-running transactions" as a feature. A transaction generall refers to a sequence of read/write operations that are guaranteed to either succeed or fail as a whole. + +Prisma offers a limited set of transactions in the form of [nested writes](). There currently is no plan to provide an API to allow a transaction API for long-running transactions. + +### Rationale + +TBD + +## Models must have at least one unique field + +Prisma currently only supports models that have at least one unique field or combination of fields. In practice, this means that every Prisma model must have either at least one of the following attributes: + +- `@id` or `@@id` for a single- or multi-field primary key constraint (max one per model) +- `@unique` or `@@unique` for a single- or multi-field unique constraint + +### Rationale + +TBD + +## Manual database connection handling + +When using Prisma, the database connections are handled on an [engine]()-level. This means they're not exposed to the developer and it's not possible to manually access them. + +### Rationale + +TBD diff --git a/content/05-more/07-roadmap.mdx b/content/05-more/07-roadmap.mdx new file mode 100644 index 0000000000..939ba5864b --- /dev/null +++ b/content/05-more/07-roadmap.mdx @@ -0,0 +1,117 @@ +--- +title: "Roadmap" +metaTitle: "" +metaDescription: "" +--- + +## Overview + +The roadmap reflects the _current plan_ for features that will be supported by Prisma in th future. The timeline for the listed features is non-committing since priorities might change and plans might need to be adjusted. + +The roadmap will be updated monthly to reflect any changes in prioritization. + +Note that the roadmap only lists "larger" features which require a significant engineering effort. For smaller features, please refer to the GitHub issues in the respective repo. You can get an overview of the features that are being worked in the current sprint by filtering for the `CURRENT-MILESTONE` label. + +## What's next? + +### Schema migrations with Prisma Migrate + +Prisma Migrate is a declarative database migration system. It lets you model your database via the Prisma schema and provides a CLI to map the Prisma schema to your database by generating the required SQL migration statements. + +Prisma Migrate is already available as an experimental feature. Learn more [here](). + +### JSON support + +Some relational databases like PostgeSQL and MySQL have a `JSON` data type to store JSON text that follows the [RFC 7159](https://tools.ietf.org/html/rfc7159) spec. + +### Visual data management with Prisma Studio + +Prisma Studio is a GUI for your database. It lets you view and edit data that's currently stored in the database. + +You can manipulate individual records and easily configure relations by connecting or disconnecting them with other records (which are referenced via foreign keys). + +Prisma Studio features a _table_- and a _tree_-view. The tree-view view is especially helpful when looking at deeply nested data. + +Prisma Studio is already available as an experimental feature. Learn more [here](). + +## Future features + +The features in this section are not ordered by priority. Because a feature comes early the list, it doesn't mean that it will be released next. + +### Aggregations in Prisma Client JS + +Prisma Client currently doesn't provide an API for aggregating data. In the future, various aggregation features that are commonly available in a database will be exposed in the Prisma Client API as well, for example: + +- Group By Primary ID/Key +- Group By Scalar +- Group By Expression +- Avg +- Median +- Max +- Min +- Count +- Sum +- Count Distinct +- Random + +### Stored procedures + +Stored procedures let you implement and invoke custom logic in your database. + +### Triggers + +SQL triggers are stored procedures that are invoked when a certain event occurs in the database. + +### Phrase and fuzzy full text Search in Prisma Client JS + +Search database rows for a certain phrase, either in the exact or in a slightly modified ("fuzzy") version. + +### Views + +SQL views are "virtual" tables. As opposed to a "real" table (that was creatd by a `CREATE TABLE` statement), a view is not physically materialized. Views are only materialized when they're referenced in a query. + +### Native database types + +Prisma currently only support a limited set of scalar types in the Prisma schema (learn more [here]()). + +However, you can still make full use of the types that are available in your database by configuring them manually and then introspecting your database schema. Prisma will map the type to the a type that is currently supported in the Prisma schema, but when querying the database the actual database type will be used. + +### Embedded types + +Embedded types let you attach structured data to a model. This data is typically stored physically next to the model data. As examples, in PostgreSQL, this can be implemented via the `JSON` type, in MongoDB, these embedded types correspond to embedded documents. + +### Prisma SDK + +Prisma provides a lot of functionality that can be consumed through various tools (e.g. Prisma Migrate). Sometimes it can be useful though to programmatically access certain functionality and bypass the extra layer of tooling. An example for such a scenario might be when you want to script a specific migration workflow in a CI/CD environment. + +For these cases, Prisma will introduce an SDK that exposes a programmatic API for the features in the Prisma tools. + +### Prisma Client in other languages + +Prisma currently only supports a single generator called `prisma-client-js`. In the future, Prisma Client will be supported in other languages as well, e.g.: + +- Go +- Python +- Elixir +- Scala +- ... + +### Custom generators + +Prisma currently only supports a single generator called `prisma-client-js`. In the future, Prisma will expose an interface for developers to write custom generators based for the Prisma schema. + +### Database connectors + +Prisma currently supports PostgreSQL, MySQL and SQLite databases as data sources. In the future, Prisma will support other databases, e.g.: + +- MongoDB +- DynamoDB +- FaunaDB +- Neo4j +- Reddis +- ... + +### Custom datasources + +Prisma currently supports PostgreSQL, MySQL and SQLite databases as data sources. In the future, it will be possible to write connectors for any data source. These data sources can be anything with an interface for data storage and/or retrieval. + From 4e2392491b97a275b222ddd44cc72d835a04d3c1 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sun, 22 Mar 2020 11:49:48 +0100 Subject: [PATCH 25/33] continue docs --- .../01-prisma-schema/06-relations.mdx | 229 +++++++++++++++--- .../01-deploying-to-zeit-now.mdx | 2 +- 2 files changed, 195 insertions(+), 36 deletions(-) diff --git a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx index 4c68d5a103..32c9c9c8a0 100644 --- a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx @@ -189,22 +189,38 @@ Foreign key relation fields are relation fields that are backed by a foreign key Virtual relation fields are relation fields in the Prisma schema that are not "manifested" in the database schema. -There are two different kinds of virtual relation fields: +There are two different kinds of virtual relation fields. -- 1-1 and 1-n relations: One side of the relation represents a foreign key, the other side is a virtual relation field. -- m-n (implicit): Both relation fields are virtual since neither of them directly maps to a foreign key. +For **1-1 and 1-n relations**, pne side of the relation represents a foreign key, the other side is a virtual relation field: -Note that the virtual relation fields in m-n-relations still have +![](https://imgur.com/kOO4eh2.png) + +For **implicit m-n-relations**, both relation fields are virtual since neither of them directly maps to a foreign key: + +![](https://imgur.com/01pxhWM.png) Prisma always requires both sides of a relation to be present, this means that one virtual relation field always needs to be added per relation. When [formatting the Prisma schema](), the formatter automatically inserts any missing virtual relation fields for you to save some typing work. -Virtual relation fields are also present in the generated [Prisma Client API]() which makes working with relations more convenient as you can traverse relationships in your code in both directions. +Virtual relation fields are also present in the generated [Prisma Client API]() which makes working with relations more convenient as you can traverse relationships in your code in both directions, for example: + +```js +// Traverse relation from `Post` to `User` via fluent API +const user = await prisma.post.findOne({ + where: { id: 1 } +}).author() + +// Traverse relation from `User` to `Post` via fluent API +const user = await prisma.user.findOne({ + where: { id: 1 } +}).posts() +``` ## The @relation attribute The `@relation` attribute can only be applied to the [relation fields]() of a Prisma model, not to its [scalar fields](). In most cases the `@relation` attribute is optional, but it can be required, e.g. when: - you need to disambiguate a relation (that's e.g. the case when you have two relations between the same models) +- you define a [self-relation](#self-relations) - you need to determine on which side of the relation a foreign key should be used - you need to control how the relation table is represented in the underlying database (e.g. use a specific name for a relation table) @@ -290,6 +306,8 @@ This 1-1-relation now expresses the following: Making the `profile` field on `User` required does not impact the schema in the underlying database since relational databases are not able to model such a constraint. This constraint is implemented and enforced by Prisma's [query engine](). +> **Note**: One-to-one [self-relations](#self-relations) must not be made required on both sides, at least one side always must be declared optional. + It's important to note that in the case of required 1-1-relations, the only way to create a new record for either `User` or `Profile` is by using [nested writes](): ```ts @@ -416,14 +434,14 @@ To summarize, these are the rules for determining which side of a 1-1-relation h - If **both relation fields are optional**, the one that comes first in the alphabet holds the foreign key. Note that this can be configured differently via the `@relation` attribute. - If **both relation fields are required**, the one that comes first in the alphabet holds the foreign key. Note that this can be configured differently via the `@relation` attribute. -Here's the summary in the form of a table assuming two generic models called `ModelA` and `ModelB`: +Here's the summary in the form of a table assuming the two relation fields of the models from before `Profile.user` and `User.profile`: -| `ModelA`'s relation field | `ModelB`'s relation field | Foreign key on | `@relation` attribute | +| `Prrofile.user` | `User.profile` | Foreign key on | `@relation` attribute | | :------------------------ | :------------------------ | ------------------------------------------------------------ | ------------------------------------------------- | -| Required | Optional | `ModelA` (because the relation field on `ModelB` is virtual) | Can't be used to determine the foreign key | -| Optional | Required | `ModelB` (because the relation field on `ModelA` is virtual) | Can't be used to determine the foreign key | -| Optional | Optional | `ModelA` (because it's first in the alphabet) | Can be used to manually determine the foreign key | -| Required | Required | `ModelA` (because it's first in the alphabet) | Can be used to manually determine the foreign key | +| Required | Optional | `Profile` (because the relation field on `User` is virtual) | Can't be used to determine the foreign key | +| Optional | Required | `User` (because the relation field on `Profile` is virtual) | Can't be used to determine the foreign key | +| Optional | Optional | `Profile` (because it's first in the alphabet) | Can be used to manually determine the foreign key | +| Required | Required | `Profile` (because it's first in the alphabet) | Can be used to manually determine the foreign key | ## One-to-many @@ -473,12 +491,12 @@ Since there's no `UNIQUE` constraint on the `author` column (foreign key), you c ### Required vs optional relation fields in one-to-many relations -A 1-n-relation always has one [virtual]() relation field (which must be a [list]()) and a foreign key relation field. In the example above, `posts Post[]` on the `User` model is virtual, `author User` holds a foreign key. +A 1-n-relation always has one [virtual relation field]() (which must be a [list]()) and a [foreign key relation field](). In the example above, `posts Post[]` on the `User` model is virtual, `author User` holds a foreign key. The relation fields in a relation can take the following forms: - the foreign key relation field can be either optional or required -- the virtual relation field must be a list and is always requireddat +- the virtual relation field must be a list and is always required So, the following variant of the example above would be _allowed_: @@ -489,8 +507,8 @@ model User { } model Post { - id Int @id @default(autoincrement()) - author User? // make `author` optional + id Int @id @default(autoincrement()) + author User? // make `author` optional } ``` @@ -510,7 +528,7 @@ model Post { ## Many-to-many -Many-to-many (m-n) relations refer to relations where zero or more records on one side of the relation can be connected to zero or more records on the other side. m-n-relations are typically modelled via [relation tables]() in a relational database. m-n-relations can be either [explicit]() or [implicit](). +Many-to-many (m-n) relations refer to relations where zero or more records on one side of the relation can be connected to zero or more records on the other side. m-n-relations are typically modelled via [relation tables]() in a relational database. m-n-relations can be either [explicit]() or [implicit]() in the Prisma schema. ### Example @@ -530,7 +548,7 @@ model Category { Notice that the `posts` field on `Category` and the `categories` field on `Post` both are [virtual](), meaning that they're not manifested in the underlying database schema. -Insttead, the implicit many-to-many relation is maintained by Prisma with a [relation table]() that's not reflected in the Prisma schema. +Instead, the implicit many-to-many relation is maintained by Prisma with a [relation table]() that's not reflected in the Prisma schema. This m-n-relation expresses the following: @@ -605,14 +623,31 @@ CREATE UNIQUE INDEX "CategoryToPost_category_post_unique" ON "CategoryToPost"("c If you're not using Prisma Migrate but obtain your data model from [introspection](), you can still make use of implicit many-to-many relations by following Prisma's conventions for relation tables. For the folowing example, assume you want to create a relation table to get an implicit many-to-many relation for two models called `Post` and `Category`. -### Table name +#### Table name + +The name of the relation table must be prefixed with an underscore: + +- **Valid**: `_CategoryToPost`, `_MyRelation` +- **Invalid**: ``CategoryToPost`, `MyRelation` + +#### Columns + +A relation table for an implicit-many-to-many relation must have exactly two columns: + +- A foreign key column that points to `Category` called `A` +- A foreign key column that points to `Post` called `B` + +The columns must be called `A` and `B` where `A` points to the model that comes first in the alphabet and `B` points to the column which comes last in the alphabet. -The name of the relation table consists of four parts: +#### Unique index + +There further must be a unique index defined on both foreign key columns: -1. An underscore as a prefix: `_` -1. TBD +```sql +CREATE UNIQUE INDEX "_CategoryToPost_AB_unique" ON "_CategoryToPost"("A" int4_ops,"B" int4_ops); +``` -Therefore, the relation name of the relation table is `_CategoryToPost`. +#### Example This the a sample SQL statement that would create the three tables including indexes (in PostgreSQL dialect): @@ -632,33 +667,157 @@ CREATE TABLE "Post" ( CREATE UNIQUE INDEX "Post_pkey" ON "Post"(id int4_ops); ``` -#### Columns - -A relation table for an implicit-many-to-many relation must have exactly two columns: +### Configuring the name of the relation table in implicit many-to-many relations -- A foreign key on `Category` that points to `Post` -- A foreign key on `Post` that points to `Category` +When using Prisma Migrate, you can configure the name of the relation table that's managed by Prisma using the `@relation` attribute. The only requirement is that it starts with an underscore. For example, if you want the relation table to be called `_MyRelationTable` instead of the default name `_CategoryToPost`, you can specify it as follows: -You can name the columns whatever you like as long as you adhere to the [naming rules]() of Prisma fields. - -#### Unique index - -There further must be a unique index defined on both foreign key columns: +```prisma +model Post { + id Int @id @default(autoincrement()) + categories Category[] @relation("MyRelationTable") +} -```sql -CREATE UNIQUE INDEX "_CategoryToPost_AB_unique" ON "_CategoryToPost"("A" int4_ops,"B" int4_ops); +model Category { + id Int @id @default(autoincrement()) + posts Post[] @relation("MyRelationTable") +} ``` ## Self-relations A relation field can also reference its own model, in this case the relation is called a _self-relation_. Self-relations can be of any cardinality, 1-1, 1-n and m-n. +Note that self-relations always require the `@relation` attribute. + ### One-to-one self-relations A one-to-one self-relation looks as follows: +```prisma +model User { + id Int @id @default(autoincrement()) + name String? + husband User? @relation("MarriagePartners") + wife User @relation("MarriagePartners") +} +``` + +This relation expresses the following: + +- "a user has zero or one _husband_ " +- "a user can have zero or one _wife_" + +Note that one-to-one self-relations can not be made required on both sides, one field has to be optional. + +In this case, the `wife` relation field is [virtual](). The `husband` field on the other hand is backed by a foreign key in the underlying database. This is implicitly determined by Prisma based on alphabetical order (`husband` comes before `wife` in the alphabet). You can adjust this by [setting the foreign key]() using the `@relation` attribute: + +```prisma +model User { + id Int @id @default(autoincrement()) + name String? + husband User? @relation("MarriagePartners") + wife User @relation("MarriagePartners", references: [id]) +} +``` + +Now the foreign key is stored on `wide` and `husband` is virtual. + ### One-to-many self relations -### Manyto-many self relations +A one-to-many self-relation looks as follows: + +```prisma +model User { + id Int @id @default(autoincrement()) + name String? + teacher User? @relation("TeacherStudents") + students User[] @relation("TeacherStudents") +} +``` + +This relation expresses the following: + +- "a user has zero or one _teachers_ " +- "a user can have zero or more _students_" + +Note that you can also require each user to have a teacher by making the `teacher` field [required](). + +### Many-to-many self relations + +A many-to-many self-relation looks as follows: + +```prisma +model User { + id Int @id @default(autoincrement()) + name String? + followedBy User[] @relation("UserFollows") + following User[] @relation("UserFollows") +} +``` + +This relation expresses the following: + +- "a user can be followed by zero or more users" +- "a user can follow zero or more users" + +### Defining multiple self-relations on the same model + +You can also define multiple self-relations on the same model at once. Taking all relations from the previous sections as example, you could define a `User` model as follows: + +```prisma +model User { + id Int @id @default(autoincrement()) + name String? + husband User? @relation("MarriagePartners") + wife User @relation("MarriagePartners") + teacher User? @relation("TeacherStudents") + students User[] @relation("TeacherStudents") + followedBy User[] @relation("UserFollows") + following User[] @relation("UserFollows") +} +``` ## Disambiguating relations + +When you define two relations between two the same models, you need to add the `@relation` attribute to disambiguate them. As an example for why that's needed, consider the following models: + +```prisma +model User { + id Int @id @default(autoincrement()) + name String? + writtenPosts Post[] + pinnedPost Post? +} + +model Post { + id Int @id @default(autoincrement()) + title String? + author User + pinnedBy User? +} +``` + +In that case, the relations are ambiguous, there are four different ways to interpet them: + +- `User.writtenPosts` ↔ `Post.author` +- `User.writtenPosts` ↔ `Post.pinnedBy` +- `User.pinnedPost` ↔ `Post.author` +- `User.pinnedPost` ↔ `Post.pinnedBy` + +To disambiguate these relations, you need to annotate the relation fields with the `@relation` attribute and provide the `name` argument. You can set any `name` (except for the empty string `""`), but it must match on both sides of the relation: + +```prisma +model User { + id Int @id @default(autoincrement()) + name String? + writtenPosts Post[] @relation("WrittenPosts") + pinnedPost Post? @relation("PinnedPost") +} + +model Post { + id Int @id @default(autoincrement()) + title String? + author User @relation("WrittenPosts") + pinnedBy User? @relation("PinnedPost") +} +``` \ No newline at end of file diff --git a/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx b/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx index 49a874d306..8e6ad4f06f 100644 --- a/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx +++ b/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx @@ -15,7 +15,7 @@ The application has the following components: - **Backend**: Serverless Node.js REST API with resource endpoints that use Prisma Client to handle database operations against a PostgreSQL database (e.g. hosted on Heroku). - **Frontend**: Static HTML page to interact with the API. -![architecture diagram](https://imgur.com/L45Ye7ze.png) +![architecture diagram](https://imgur.com/cR9V9v7.png) The focus of this guide is showing how Prisma integrates with ZEIT Now. The starting point will the [Prisma ZEIT Now example](https://github.com/prisma/prisma-examples/tree/prisma2/deployment-platforms/zeit-now) which has a couple of REST endpoints preconfigured as serverless functions and a static page. From 2d2fbc7d265ed0bfd9ac4630c32ee1ef8ecc32e4 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sun, 22 Mar 2020 11:51:12 +0100 Subject: [PATCH 26/33] continue docs --- .../{04-relations.mdx => 04-relation-queries.mdx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename content/03-reference/01-tools-and-interfaces/02-prisma-client/{04-relations.mdx => 04-relation-queries.mdx} (100%) diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relations.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx similarity index 100% rename from content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relations.mdx rename to content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx From 43cb52d42a7a4b1409d69a65cd674f76c4a780cd Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sun, 22 Mar 2020 13:08:20 +0100 Subject: [PATCH 27/33] continue docs --- .../01-prisma-schema/06-relations.mdx | 12 +- .../02-prisma-client/04-relation-queries.mdx | 109 +++++++++++++++++- 2 files changed, 113 insertions(+), 8 deletions(-) diff --git a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx index 32c9c9c8a0..c996969ca1 100644 --- a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/06-relations.mdx @@ -205,14 +205,14 @@ Virtual relation fields are also present in the generated [Prisma Client API]() ```js // Traverse relation from `Post` to `User` via fluent API -const user = await prisma.post.findOne({ - where: { id: 1 } -}).author() +const user = await prisma.post + .findOne({ where: { id: 1 } }) + .author() // Traverse relation from `User` to `Post` via fluent API -const user = await prisma.user.findOne({ - where: { id: 1 } -}).posts() +const user = await prisma.user + .findOne({ where: { id: 1 } }) + .posts() ``` ## The @relation attribute diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx index 5717a0335a..3246b48202 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx @@ -1,7 +1,112 @@ --- -title: "Relations" +title: "Relation queries" metaTitle: "" metaDescription: "" --- -Coming soon 🔜 +## Overview + +One of the main features of Prisma Client is its API for sending relation queries. Relation queries refer to queries that operate on a [relation]() between two or more models: + +- Fluent API for traversing relations +- Nested writes with [transactional]() guarantees +- Nested reads (sometimes referred to as _eager loading_) via [`select`]() and [`include`]() +- Relation filters (filters on related objects) + +This page explains which relation queries exist and how to use them. + +The examples on this page based on the following data model: + +```prisma +datasource postgresql { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + +model User { + id Int @id @default(autoincrement()) + posts Post[] + profile Profile? +} + +model Profile { + id Int @id @default(autoincrement()) + user User +} + +model Post { + id Int @id @default(autoincrement()) + author User + categories Category[] +} + +model Category { + id Int @id @default(autoincrement()) + posts Post[] +} +``` + +> **Note**. This schema is the same as the [example data model](./data-modeling.md/#example) but has all [scalar fields](./data-modeling.md/#scalar-types) removed so you can focus on the relation fields. + +## Fluent API + +The fluent API lets you _fluently_ traverse the [relations]() of your models via function calls. Note that the _last_ function call determines the return type of the entire query (the respective type annotations are added in the code snippets below to make that explicit). + +This query returns all `Post` records by a specific `User`: + +```ts +const postsByUser: Post[] = await prisma.user + .findOne({ where: { email: 'alice@prisma.io' } }) + .posts() +``` + +Note that this call is equivalent to this Prisma Client query: + +```ts +const postsByUser = await prisma.post.findMany({ + where: { author: { email: "alice@prisma.io" } } +}) +``` + +The main difference between the two is that the fluent API call is translated into two separaye database queries while the other one only generates a single query. + +This request returns all categories by a specific post: + +```ts +const categoriesOfPost: Category[] = await prisma.post + .findOne({ where: { id: 1 } }) + .categories() +``` + +Note that you can chain as many queries as you like. In this example, the chanining start at `Profile` and goes over `User` to `Post`: + +```ts +const posts: Post[] = await prisma.profile + .findOne({ where: { id: 1 } }) + .user() + .posts() +} +``` + +The only requirement for chaining is that the previous function call must return only a _single object_ (e.g. as returned by a `findOne` query or a "to-one relation" like `profile.user()`). + +The following query is **not possible** because `findMany` does not return a single object but a list: + +```ts +// This query is illegal +const posts = await prisma.user + .findMany() + .posts() +} +``` + +## Nested writes + +## Nested reads + +## Relation filters + From 4ee0062dc312c3525a6dc9b907ad5a28fcab6d59 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sun, 22 Mar 2020 20:03:36 +0100 Subject: [PATCH 28/33] continue docs --- .../02-prisma-client/04-relation-queries.mdx | 423 ++++++++++++++++++ 1 file changed, 423 insertions(+) diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx index 3246b48202..6b2d35a570 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx @@ -106,7 +106,430 @@ const posts = await prisma.user ## Nested writes +Nested writes provide a way for writing relational data in your database. They further provide [transactional]() guarantees for creating, updating or deleting data across multiple tables in a single Prisma Client query. + +Nested writes can be nested arbitrarily deep. + +Nested writes are available for [relation fields]() when using the model's `create` or `update` query. The following nested write options are available per query: + +| Query | Option | Description | +| :-- | :-- | :-- | +| | | + + +### One-to-one relations + +This section shows examples for nested writes on one-to-one relations. It uses the `User` ↔ `Profile` relation from the sample data model above. For illustration purposes, the `email` and `bio` fields have been added: + +```prisma +model User { + id Int @id @default(autoincrement()) + email String @unique + profile Profile +} + +model Profile { + id Int @id @default(autoincrement()) + bio String + user User? +} +``` + +One-to-one relation fields (e.g. `profile` on `User` in the sample data model above) +- `create` + - `create`: Create a new user and a new profile + - `connect`: Create a new user and connect it to an existing profile +- `update` + - `create`: Update an existing user by creating a new profile + - `connect`: Update an an existing user by connecting it to an existing profile + - `update`: Update an existing user by updating their existing profile + - `upsert`: Update an existing user by updating their existing profile or by creating a new profile + - `delete` (only if relation is optional): Update an existing user by deleting their existing profile + - `disconnect` (only if relation is optional): Update an existing user by removing the connection to their existing profile + + +**Create a new `User` record with a new `Profile` record**: + +```ts +const user = await prisma.user.create({ + data: { + email: "alice@prisma.io", + profile: { + create: { bio: "Hello World" } + } + } +}) +``` + +This example uses the `user` model property, but you could also run the query from the `profile` side: + +```ts +const user = await prisma.profile.create({ + data: { + bio: "Hello World", + user: { + create: { email: "alice@prisma.io", } + } + } +}) +``` + +**Create a new `Profile` record and connect it to an existing `User` record** + +```ts +const user = await prisma.profile.create({ + data: { + bio: "Hello World", + user: { + connect: { email: "alice@prisma.io" } + } + } +}) +``` + +Note that this requires that a `User` record with an `email` of `"alice@prisma.io"` already exists in the database. If that's not the case, the query will fail with an exception. + +You can provide any [unique]() or [ID]() property to the `connect` option, so in this case you could also provide the `id` fied to identify the target `User` record: + +```ts +const user = await prisma.profile.create({ + data: { + bio: "Hello World", + user: { + connect: { id: 42 } + } + } +}) +``` + +**Update an existing `User` record by creating a new `Profile` record** + +```ts +const user = await prisma.user.update({ + where: { email: "alice@prisma.io" }, + data: { + profile: { + create: { bio: "Hello World" } + } + } +}) +``` + +**Update an existing `User` record by connecting it to an existing `Profile` record** + +```ts +const user = await prisma.user.update({ + where: { email: "alice@prisma.io" }, + data: { + profile: { + connect: { id: 24 } + } + } +}) +``` + +**Update an existing `User` record by updating the `Profile` record it's connected to** + +```ts +const user = await prisma.user.update({ + where: { email: "alice@prisma.io" }, + data: { + profile: { + update: { bio: "Hello World" } + } + } +}) +``` + +**Update an existing `User` record by updating the `Profile` record it's connected to or creating a new one (_upsert_)** + +```ts +const user = await prisma.user.update({ + where: { email: "alice@prisma.io" }, + data: { + profile: { + upsert: { + create: { bio: "Hello World" }, + update: { bio: "Hello World" } + } + } + } +}) +``` + +**Update an existing `User` record by deleting the `Profile` record it's connected to** + +```ts +const user = await prisma.user.update({ + where: { email: "alice@prisma.io" }, + data: { + profile: { + delete: true + } + } +}) +``` + +**Update an existing `User` record by disconnecting the `Profile` record it's connected to** + +```ts +const user = await prisma.user.update({ + where: { email: "bob @prisma.io" }, + data: { + profile: { + disconnect: true + } + } +}) +``` + +Note that this query is actually illegal with the data model from above because the `user` field on `Profile` is required. In order to make this query succeed, you'd need to make both relation fields optional: + +```prisma +model User { + id Int @id @default(autoincrement()) + profile Profile? +} + +model Profile { + id Int @id @default(autoincrement()) + user User? +} +``` + +### One-to-many relations + +This section shows examples for nested writes on one-to-many relations. It uses the `User` ↔ `Post` relation from the sample data model above. For illustration purposes, the `email`, `title` and `published fields have been added: + +```prisma +model User { + id Int @id @default(autoincrement()) + email String @unique + posts Post[] +} + +model Post { + id Int @id @default(autoincrement()) + title String + published Boolean @default(false) + auhtor User? +} +``` + +One-to-many relation fields (e.g. `posts` on `User` in the sample data model above): +- `create` + - `create`: Create a new user and one or more new posts + - `connect`: Create a new user and connect it to one or more existing posts +- `update` + - `create`: Update an existing user by creating one or more new posts + - `connect`: Update an existing user by connecting it to one or more existing posts + - `update`: Update an existing user by updating one or more of their existing posts + - `upsert`: Update an existing user by updating one or more of their existing posts or by creating one or more new posts + - `delete`: Update an existing user by deleting one or more of their existing posts + - `disconnect`: Update an existing by removing the connection(s) to one or more of their existing posts + - `set`: Update an existing user by replacing their existing posts with one or more existing posts + - `updateMany`: Update an existing user by updating one or more of their existing posts + - `deleteMany`: Update an existing user by deleting one or more of their existing posts + + +**Create a new `User` record with a new `Post` record**: + +```ts +const user = await prisma.user.create({ + data: { + email: "alice@prisma.io", + posts: { + create: { title: "Hello World" } + } + } +}) +``` + +This example uses the `user` model property, but you could also run the query from the `post` side: + +```ts +const user = await prisma.post.create({ + data: { + title: "Hello World", + author: { + create: { email: "alice@prisma.io", } + } + } +}) +``` + +**Create a new `User` record with two new `Post` records**: + +Because it's a one-to-many relation, you can also create several `Post` records at once by passing an array to `create`: + +```ts +const user = await prisma.user.create({ + data: { + email: "alice@prisma.io", + posts: { + create: [ + { title: "This is my first post" }, + { title: "Here comes a second post" } + ] + } + } +}) +``` + +**Create a new `Post` record and connect it to an existing `User` record** + +```ts +const user = await prisma.post.create({ + data: { + title: "Hello World", + author: { + connect: { email: "alice@prisma.io" } + } + } +}) +``` + +Note that this requires that a `User` record with an `email` of `"alice@prisma.io"` already exists in the database. If that's not the case, the query will fail with an exception. + +You can provide any [unique]() or [ID]() property to the `connect` option, so in this case you could also provide the `id` fied to identify the target `User` record: + +```ts +const user = await prisma.post.create({ + data: { + title: "Hello World", + author: { + connect: { id: 42 } + } + } +}) +``` + +**Update an existing `User` record by creating a new `Post` record** + +```ts +const user = await prisma.user.update({ + where: { email: "alice@prisma.io" }, + data: { + posts: { + create: { title: "Hello World" } + } + } +}) +``` + +**Update an existing `User` record by connecting it to two existing `Post` records** + +```ts +const user = await prisma.user.update({ + where: { email: "alice@prisma.io" }, + data: { + posts: { + connect: [ + { id: 24 }, + { id: 42 } + ] + } + } +}) +``` + +**Update an existing `User` record by updating two `Post` records it's connected to** + +```ts +const user = await prisma.user.update({ + where: { email: 'alice@prisma.io' }, + data: { + posts: { + update: [ + { + data: { published: true }, + where: { id: 32 }, + }, + { + data: { published: true }, + where: { id: 23 }, + }, + ], + }, + }, +}) +``` + +**Update an existing `User` record by updating two `Post` record it's connected to or creating new ones (_upsert_)** + +```ts +const user = await prisma.user.update({ + where: { email: "alice@prisma.io" }, + data: { + posts: { + upsert: [{ + create: { title: "This is my first post" }, + update: { title: "This is my first post" }, + where: { id: 32} + }, { + create: { title: "This is mt second post" }, + update: { title: "This is mt second post" }, + where: { id: 23} + }] + } + } +}) +``` + +**Update an existing `User` record by deleting two `Post` records it's connected to** + +```ts +const user = await prisma.user.update({ + where: { email: 'alice@prisma.io' }, + data: { + posts: { + delete: [ + { id: 34 }, + { id: 36 }, + ], + }, + }, +}) +``` + +**Update an existing `User` record by disconnecting two `Post` records it's connected to** + +```ts +const user = await prisma.user.update({ + where: { email: 'alice@prisma.io' }, + data: { + posts: { + disconnect: [ + { id: 44 }, + { id: 46 }, + ], + }, + }, +}) +``` + +**Update an existing `User` record by disconnecting any previous `Post` records and connect two other exiting ones** + +```ts +const user = await prisma.user.update({ + where: { email: 'alice@prisma.io' }, + data: { + posts: { + set: [ + {id: 32}, + {id: 42}, + ] + }, + }, +}) +``` + + ## Nested reads +With nested reads, you can modify the structures of the model objects that are returned by your Prisma Client queries by including their relations. In [ORM]() terminoloy, this is sometimes called _eager loading_. + +You can load relations of your models with the [`include`]() and [`select`]() options which you can pass to any Prisma Client query (except for the batch operations `updateMany` and `deleteMany`). `include` is more commonly used for relations, `select` is used for selecting specific fields. + ## Relation filters From 92905b6309ec57d18ab858425502bdec5c4ba059 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Sun, 22 Mar 2020 20:36:18 +0100 Subject: [PATCH 29/33] continue docs --- .../02-prisma-client/04-relation-queries.mdx | 83 ++++++++++++++++++- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx index 6b2d35a570..060063a577 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relation-queries.mdx @@ -72,7 +72,7 @@ const postsByUser = await prisma.post.findMany({ }) ``` -The main difference between the two is that the fluent API call is translated into two separaye database queries while the other one only generates a single query. +The main difference between the two is that the fluent API call is translated into two separate database queries while the other one only generates a single query. This request returns all categories by a specific post: @@ -104,6 +104,40 @@ const posts = await prisma.user } ``` + +## Relation filters + +A relation filter is a filter operation that's applied to a related object of a model. Relation filter options can be passed to the last chained query in a fluent API call if it returns a [list](). + +**Retrieve all `Post` records of a particular `User` record that start with "Hello"** + +```ts +const posts: Post[] = await prisma.user + .findOne({ + where: { email: 'ada@prisma.io' }, + }) + .posts({ + where: { + title: { startsWith: 'Hello' }, + }, + }) +``` + +Note that this query is equivalent to the following one which is initiated via the `post` instead of the `user` field (i.e. it doesn't use the fluent API): + +```ts +const posts = await prisma.post.findMany({ + where: { + author: { email: "bob@prisma.io"}, + title: { startsWith: "Hello" } + } +}) +console.log(posts) +``` + +The main difference between the two is that the fluent API call is translated into two separate database queries while the other one only generates a single query. + + ## Nested writes Nested writes provide a way for writing relational data in your database. They further provide [transactional]() guarantees for creating, updating or deleting data across multiple tables in a single Prisma Client query. @@ -529,7 +563,50 @@ const user = await prisma.user.update({ With nested reads, you can modify the structures of the model objects that are returned by your Prisma Client queries by including their relations. In [ORM]() terminoloy, this is sometimes called _eager loading_. -You can load relations of your models with the [`include`]() and [`select`]() options which you can pass to any Prisma Client query (except for the batch operations `updateMany` and `deleteMany`). `include` is more commonly used for relations, `select` is used for selecting specific fields. +You can load relations of your models with the [`include`]() and [`select`]() options which you can pass to _any_ Prisma Client query (except for the batch operations `updateMany` and `deleteMany`), . `include` is more commonly used for relations, `select` is used for selecting specific fields. -## Relation filters +**Include the `posts` and `profile` relation when loading `User` records** + +```ts +const users = await prisma.user.findMany({ + include: { + posts: true, + profile: true + } +}) +``` +**Include the `posts` relation on the returned objects when creating a new `User` record with two `Post` records** + +```ts +const user = await prisma.user.create({ + data: { + email: "alice@prisma.io", + posts: { + create: [ + { title: "This is my first post" }, + { title: "Here comes a second post" } + ] + } + }, + include: { posts: true } +}) +``` + +**Retrieve deeply nested data by loading several levels of relations** + +```ts +const users = await prisma.user.findMany({ + include: { + posts: { + include: { + categories: { + include: { + posts: true, + }, + }, + }, + }, + }, +}) +``` From 5efba45e8e4890d0c3b802d7ba2a79568326c525 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Mon, 23 Mar 2020 07:42:11 +0100 Subject: [PATCH 30/33] continue docs --- content/02-understand-prisma/02-features.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/content/02-understand-prisma/02-features.mdx b/content/02-understand-prisma/02-features.mdx index f478b646b0..6a7a386a15 100644 --- a/content/02-understand-prisma/02-features.mdx +++ b/content/02-understand-prisma/02-features.mdx @@ -88,6 +88,7 @@ Lock option (MySQL): | Authorization and user management | Yes | Yes | No | Not yet | Not yet | Not yet | | JSON support | Yes | No | No | Not yet | Not yet | Not yet | | Fuzzy/Phrase Full Text Search | Yes | Yes | No | Not yet | Not yet | Not yet | +| Table inheritance | Yes | No | No | Not yet | Not yet | Yes | ## Functions From 4c48f2d4145043ddfbf8bc352af1d90c1774c539 Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Mon, 23 Mar 2020 08:29:34 +0100 Subject: [PATCH 31/33] continue docs --- .../02-prisma-client/08-generated-types.mdx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx index 2d1c2a7247..88d837cc8a 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx @@ -72,21 +72,20 @@ type UserPersonalData = { }; ``` -While this is certainly feasible, this approach increases the maintenance burden upon changes to the Prisma schema as you need to manually maintain the types. A cleaner solution to this is to use the `UserGetIncludePayload` and `UserGetSelectPayload` types that are generated and exposed by Prisma Client: +While this is certainly feasible, this approach increases the maintenance burden upon changes to the Prisma schema as you need to manually maintain the types. A cleaner solution to this is to use the `UserGetPayload` type that is generated and exposed by Prisma Client: ```ts -import { UserGetIncludePayload, UserGetSelectPayload } from "@prisma/client"; +import { UserGetPayload } from "@prisma/client"; // Define a type that includes the relation to `Post` -type UserWithPosts = UserGetIncludePayload<{ - posts: true; -}>; +type UserWithPosts = UserGetPayload<{ + include: { posts: true } +}> // Define a type that only contains a subset of the scalar fields -type UserPersonalData = UserGetSelectPayload<{ - email: true; - name: true; -}>; +type UserPersonalData = UserGetPayload<{ + select: { email: true; name: true } +}> ``` The main benefits of the latter approach are: From bbaaa1b538f687affaf43ce96ecb71b509d4ed0a Mon Sep 17 00:00:00 2001 From: Nikolas Burk Date: Mon, 23 Mar 2020 09:08:29 +0100 Subject: [PATCH 32/33] start with prisma migrate docs --- .../01-tools-and-interfaces/01-prisma-schema/index.mdx | 1 - .../01-tools-and-interfaces/03-prisma-migrate/index.mdx | 3 ++- .../03-prisma-migrate/migration-scenarios.mdx | 0 .../03-prisma-migrate/what-is-prisma-migrate.mdx | 0 4 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 content/03-reference/01-tools-and-interfaces/03-prisma-migrate/migration-scenarios.mdx create mode 100644 content/03-reference/01-tools-and-interfaces/03-prisma-migrate/what-is-prisma-migrate.mdx diff --git a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/index.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/index.mdx index a57f6ac356..1047f7e9e8 100644 --- a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/index.mdx @@ -2,5 +2,4 @@ title: "Prisma schema" metaTitle: "" metaDescription: "" -experimental: true --- diff --git a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx index 2ba2096d40..f0a6a2087e 100644 --- a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx @@ -2,5 +2,6 @@ title: "Prisma Migrate" metaTitle: "" metaDescription: "" -experimental: true +experimtental: true --- + diff --git a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/migration-scenarios.mdx b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/migration-scenarios.mdx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/what-is-prisma-migrate.mdx b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/what-is-prisma-migrate.mdx new file mode 100644 index 0000000000..e69de29bb2 From 6879e8d566aef4e1cc10043c39de8bcfc8f53a0d Mon Sep 17 00:00:00 2001 From: Nilu Date: Mon, 23 Mar 2020 10:25:11 +0100 Subject: [PATCH 33/33] Added prettify rules --- .prettierrc | 2 +- content/01-getting-started/02-quickstart.mdx | 8 ++-- .../01-add-to-an-existing-project.mdx | 6 +-- .../02-start-from-scratch-sql-migrations.mdx | 36 ++++++++--------- .../03-start-from-scratch-prisma-migrate.mdx | 16 ++++---- .../03-setup-prisma/index.mdx | 8 ++-- content/01-getting-started/index.mdx | 6 +-- .../02-understand-prisma/01-introduction.mdx | 6 +-- content/02-understand-prisma/02-features.mdx | 6 +-- .../index.mdx | 6 +-- .../04-is-prisma-an-orm.mdx | 20 +++++----- .../02-understand-prisma/05-data-modeling.mdx | 10 ++--- content/02-understand-prisma/index.mdx | 6 +-- .../01-what-is-the-prisma-schema.mdx | 8 ++-- .../01-schema/02-data-sources.mdx | 6 +-- .../01-schema/03-generators.mdx | 6 +-- .../01-schema/05-models.mdx | 8 ++-- .../01-schema/06-relations.mdx | 6 +-- .../01-schema/index.mdx | 6 +-- .../01-generating-prisma-client.mdx | 14 +++---- .../02-configuring-the-prisma-client-api.mdx | 18 ++++----- .../02-prisma-client/04-relations.mdx | 6 +-- .../02-prisma-client/05-field-selection.mdx | 40 +++++++++---------- .../06-raw-database-access.mdx | 16 ++++---- .../07-connection-management.mdx | 6 +-- .../02-prisma-client/08-generated-types.mdx | 10 ++--- .../02-prisma-client/09-filtering.mdx | 6 +-- .../02-prisma-client/10-ordering.mdx | 6 +-- .../02-prisma-client/11-pagination.mdx | 6 +-- .../02-prisma-client/13-debugging.mdx | 6 +-- .../02-prisma-client/14-error-formatting.mdx | 8 ++-- .../02-prisma-client/15-transactions.mdx | 16 ++++---- .../02-prisma-client/16-deployment.mdx | 6 +-- .../02-prisma-client/17-query-engine.mdx | 8 ++-- .../18-usage-with-module-bundlers.mdx | 6 +-- .../02-prisma-client/19-api.mdx | 6 +-- .../02-prisma-client/index.mdx | 6 +-- .../03-prisma-migrate/index.mdx | 6 +-- .../04-introspection.mdx | 6 +-- .../05-prisma-cli/01-installation.mdx | 6 +-- .../05-prisma-cli/02-command-reference.mdx | 6 +-- .../05-prisma-cli/index.mdx | 6 +-- .../01-tools-and-interfaces/index.mdx | 6 +-- .../02-database-connectors/01-postgresql.mdx | 6 +-- .../02-database-connectors/02-mysql.mdx | 6 +-- .../02-database-connectors/03-sqlite.mdx | 6 +-- .../02-database-connectors/index.mdx | 6 +-- .../03-reference/03-more/01-editor-setup.mdx | 6 +-- content/03-reference/03-more/02-telemetry.mdx | 6 +-- content/03-reference/03-more/index.mdx | 6 +-- content/03-reference/index.mdx | 6 +-- .../01-postgresql.mdx | 6 +-- .../01-setting-up-a-database/02-mysql.mdx | 6 +-- .../01-setting-up-a-database/03-sqlite.mdx | 6 +-- .../01-setting-up-a-database/index.mdx | 4 +- .../01-postgresql.mdx | 6 +-- .../02-mysql.mdx | 6 +-- .../03-sqlite.mdx | 6 +-- .../02-importing-and-exporting-data/index.mdx | 4 +- .../03-primary-keys/01-postgresql.mdx | 6 +-- .../03-primary-keys/02-mysql.mdx | 6 +-- .../03-primary-keys/03-sqlite.mdx | 6 +-- .../03-primary-keys/index.mdx | 4 +- .../index.mdx | 4 +- .../05-foreign-keys/02-mysql.mdx | 18 ++++----- .../05-foreign-keys/index.mdx | 4 +- .../06-cascading-deletes/index.mdx | 4 +- .../07-data-validation/01-postgresql.mdx | 14 +++---- .../07-data-validation/02-mysql.mdx | 6 +-- .../07-data-validation/03-sqlite.mdx | 6 +-- .../07-data-validation/index.mdx | 4 +- .../04-guides/01-database-workflows/index.mdx | 4 +- .../01-deploying-to-zeit-now.mdx | 6 +-- .../02-deploying-to-aws-lambda.mdx | 6 +-- .../02-deployment/03-deploying-to-heroku.mdx | 6 +-- content/04-guides/02-deployment/index.mdx | 6 +-- content/04-guides/index.mdx | 6 +-- src/components/customMdx/code.tsx | 6 +-- src/components/customMdx/copy.tsx | 10 ++--- src/components/customMdx/index.tsx | 18 ++++----- src/components/customMdx/pre.tsx | 14 +++---- src/components/footer.tsx | 38 +++++++++--------- src/components/header.tsx | 40 +++++++++---------- src/components/image.tsx | 6 +-- src/components/layout.css | 26 ++++++------ src/components/layout.tsx | 24 +++++------ src/components/pageBottom.tsx | 12 +++--- src/components/seo.tsx | 4 +- src/components/sidebar/index.tsx | 10 ++--- src/components/sidebar/tree.tsx | 14 +++---- src/components/sidebar/treeNode.tsx | 26 ++++++------ src/components/toc.tsx | 16 ++++---- src/components/topSection.tsx | 8 ++-- src/hooks/useAllArticlesQuery.ts | 4 +- src/hooks/useLayoutQuery.ts | 4 +- src/hooks/useTOCQuery.ts | 4 +- src/icons/ArrowDown.tsx | 2 +- src/icons/ArrowEmail.tsx | 2 +- src/icons/ArrowRight.tsx | 2 +- src/icons/Copy.tsx | 2 +- src/icons/Down.tsx | 2 +- src/icons/Email.tsx | 2 +- src/icons/Facebook.tsx | 2 +- src/icons/Git.tsx | 2 +- src/icons/GitGrey.tsx | 2 +- src/icons/Logo.tsx | 2 +- src/icons/PrismaLogoGrey.tsx | 2 +- src/icons/Search.tsx | 2 +- src/icons/Slack.tsx | 2 +- src/icons/Twitter.tsx | 2 +- src/icons/Up.tsx | 2 +- src/icons/Youtube.tsx | 2 +- src/interfaces/AllArticles.interface.ts | 4 +- src/interfaces/Article.interface.ts | 2 +- src/interfaces/TOC.interface.ts | 2 +- src/layouts/articleLayout.tsx | 30 +++++++------- src/pages/404.tsx | 4 +- src/pages/index.tsx | 18 ++++----- src/utils/stringify.ts | 16 ++++---- 119 files changed, 501 insertions(+), 501 deletions(-) diff --git a/.prettierrc b/.prettierrc index 40986f84b9..e33248810f 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,7 +1,7 @@ { "printWidth": 100, "jsxBracketSameLine": false, - "singleQuote": false, + "singleQuote": true, "tabWidth": 2, "trailingComma": "es5" } diff --git a/content/01-getting-started/02-quickstart.mdx b/content/01-getting-started/02-quickstart.mdx index 7da792f10d..c04e6c6cff 100644 --- a/content/01-getting-started/02-quickstart.mdx +++ b/content/01-getting-started/02-quickstart.mdx @@ -1,8 +1,8 @@ --- -title: "Quickstart" -metaTitle: "" -metaDescription: "" -duration: "5 min" +title: 'Quickstart' +metaTitle: '' +metaDescription: '' +duration: '5 min' --- Coming 🔜 diff --git a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx index 32e158faca..42149e1c2d 100644 --- a/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx +++ b/content/01-getting-started/03-setup-prisma/01-add-to-an-existing-project.mdx @@ -1,7 +1,7 @@ --- -title: "Add Prisma to an existing project" -metaTitle: "" -metaDescription: "" +title: 'Add Prisma to an existing project' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx index e483d34d82..490d349e18 100644 --- a/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx +++ b/content/01-getting-started/03-setup-prisma/02-start-from-scratch-sql-migrations.mdx @@ -1,7 +1,7 @@ --- -title: "Start from scratch (SQL migrations)" -metaTitle: "" -metaDescription: "" +title: 'Start from scratch (SQL migrations)' +metaTitle: '' +metaDescription: '' --- **Note: The content of this page is temporary and will be updated soon.** @@ -82,7 +82,7 @@ Follow these steps for an initial Prisma setup: 1. Run `touch index.ts` to create a source file and add the following code: ```ts - import { PrismaClient } from "@prisma/client"; + import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); @@ -90,12 +90,12 @@ Follow these steps for an initial Prisma setup: async function main() { const user1 = await prisma.user.create({ data: { - email: "alice@prisma.io", - name: "Alice", + email: 'alice@prisma.io', + name: 'Alice', post: { create: { - title: "Watch the talks from Prisma Day 2019", - content: "https://www.prisma.io/blog/z11sg6ipb3i1/", + title: 'Watch the talks from Prisma Day 2019', + content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', }, }, }, @@ -194,7 +194,7 @@ Follow these steps for an initial Prisma setup: 1. Run `touch index.ts` to create a source file and add the following code: ```ts - import { PrismaClient } from "@prisma/client"; + import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); @@ -202,12 +202,12 @@ Follow these steps for an initial Prisma setup: async function main() { const user1 = await prisma.user.create({ data: { - email: "alice@prisma.io", - name: "Alice", + email: 'alice@prisma.io', + name: 'Alice', post: { create: { - title: "Watch the talks from Prisma Day 2019", - content: "https://www.prisma.io/blog/z11sg6ipb3i1/", + title: 'Watch the talks from Prisma Day 2019', + content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', }, }, }, @@ -299,7 +299,7 @@ Follow these steps for an initial Prisma setup: 1. Run `touch index.ts` to create a source file and add the following code: ```ts - import { PrismaClient } from "@prisma/client"; + import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); @@ -307,12 +307,12 @@ Follow these steps for an initial Prisma setup: async function main() { const user1 = await prisma.user.create({ data: { - email: "alice@prisma.io", - name: "Alice", + email: 'alice@prisma.io', + name: 'Alice', post: { create: { - title: "Watch the talks from Prisma Day 2019", - content: "https://www.prisma.io/blog/z11sg6ipb3i1/", + title: 'Watch the talks from Prisma Day 2019', + content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', }, }, }, diff --git a/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx b/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx index 891eecae94..4031d1c8ab 100644 --- a/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx +++ b/content/01-getting-started/03-setup-prisma/03-start-from-scratch-prisma-migrate.mdx @@ -1,7 +1,7 @@ --- -title: "Start from scratch (Prisma Migrate)" -metaTitle: "" -metaDescription: "" +title: 'Start from scratch (Prisma Migrate)' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -85,7 +85,7 @@ Follow these steps for an initial Prisma setup: 1. Run `touch index.ts` to create a source file and add the following code: ```ts - import { PrismaClient } from "@prisma/client"; + import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); @@ -93,12 +93,12 @@ Follow these steps for an initial Prisma setup: async function main() { const user1 = await prisma.user.create({ data: { - email: "alice@prisma.io", - name: "Alice", + email: 'alice@prisma.io', + name: 'Alice', posts: { create: { - title: "Watch the talks from Prisma Day 2019", - content: "https://www.prisma.io/blog/z11sg6ipb3i1/", + title: 'Watch the talks from Prisma Day 2019', + content: 'https://www.prisma.io/blog/z11sg6ipb3i1/', }, }, }, diff --git a/content/01-getting-started/03-setup-prisma/index.mdx b/content/01-getting-started/03-setup-prisma/index.mdx index 8d5c42d18d..743d056efe 100644 --- a/content/01-getting-started/03-setup-prisma/index.mdx +++ b/content/01-getting-started/03-setup-prisma/index.mdx @@ -1,6 +1,6 @@ --- -title: "Setup Prisma" -metaTitle: "" -metaDescription: "" -duration: "15 min" +title: 'Setup Prisma' +metaTitle: '' +metaDescription: '' +duration: '15 min' --- diff --git a/content/01-getting-started/index.mdx b/content/01-getting-started/index.mdx index 3d9a0c5135..c6cc9c5dc2 100644 --- a/content/01-getting-started/index.mdx +++ b/content/01-getting-started/index.mdx @@ -1,5 +1,5 @@ --- -title: "Getting started" -metaTitle: "Getting started" -metaDescription: "Getting started" +title: 'Getting started' +metaTitle: 'Getting started' +metaDescription: 'Getting started' --- diff --git a/content/02-understand-prisma/01-introduction.mdx b/content/02-understand-prisma/01-introduction.mdx index 423503d698..6953f5b806 100644 --- a/content/02-understand-prisma/01-introduction.mdx +++ b/content/02-understand-prisma/01-introduction.mdx @@ -1,7 +1,7 @@ --- -title: "Introduction" -metaTitle: "" -metaDescription: "" +title: 'Introduction' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/02-understand-prisma/02-features.mdx b/content/02-understand-prisma/02-features.mdx index f478b646b0..b9e3ab2a41 100644 --- a/content/02-understand-prisma/02-features.mdx +++ b/content/02-understand-prisma/02-features.mdx @@ -1,7 +1,7 @@ --- -title: "Features" -metaTitle: "" -metaDescription: "" +title: 'Features' +metaTitle: '' +metaDescription: '' --- **Note: The content of this page is still in progress.** diff --git a/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx b/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx index 22e4d56063..1b5a9f46a4 100644 --- a/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx +++ b/content/02-understand-prisma/03-how-prisma-fits-into-your-stack/index.mdx @@ -1,5 +1,5 @@ --- -title: "How Prisma fits into your stack" -metaTitle: "How Prisma fits into your stack" -metaDescription: "How Prisma fits into your stack" +title: 'How Prisma fits into your stack' +metaTitle: 'How Prisma fits into your stack' +metaDescription: 'How Prisma fits into your stack' --- diff --git a/content/02-understand-prisma/04-is-prisma-an-orm.mdx b/content/02-understand-prisma/04-is-prisma-an-orm.mdx index d8f3a1d5b9..15595a448a 100644 --- a/content/02-understand-prisma/04-is-prisma-an-orm.mdx +++ b/content/02-understand-prisma/04-is-prisma-an-orm.mdx @@ -1,7 +1,7 @@ --- -title: "Is Prisma an ORM?" -metaTitle: "" -metaDescription: "" +title: 'Is Prisma an ORM?' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -136,8 +136,8 @@ Model instances represent database records and contain three important things: You can fetch and update a model instance with Sequelize as follows: ```js -const ada = await User.findOne({ where: { firstName: "Ada" } }); -ada.lastName = "Lovelace"; +const ada = await User.findOne({ where: { firstName: 'Ada' } }); +ada.lastName = 'Lovelace'; await ada.save(); ada.getFullName(); // Ada Lovelace ``` @@ -158,7 +158,7 @@ Assuming you were starting from scratch, this is what a full workflow would look // migrations/20191217102908-create-user.js module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.createTable("Users", { + return queryInterface.createTable('Users', { id: { allowNull: false, autoIncrement: true, @@ -167,18 +167,18 @@ module.exports = { }, firstName: { type: Sequelize.STRING, - field: "first_name", + field: 'first_name', }, lastName: { type: Sequelize.STRING, - field: "last_name", + field: 'last_name', }, email: { type: Sequelize.STRING, }, emailConfirmed: { type: Sequelize.BOOLEAN, - field: "email_confirmed", + field: 'email_confirmed', allowNull: false, defaultValue: false, }, @@ -188,7 +188,7 @@ module.exports = { }); }, down: (queryInterface, Sequelize) => { - return queryInterface.dropTable("Users"); + return queryInterface.dropTable('Users'); }, }; ``` diff --git a/content/02-understand-prisma/05-data-modeling.mdx b/content/02-understand-prisma/05-data-modeling.mdx index c162506025..b7f93b8845 100644 --- a/content/02-understand-prisma/05-data-modeling.mdx +++ b/content/02-understand-prisma/05-data-modeling.mdx @@ -1,7 +1,7 @@ --- -title: "Data modeling" -metaTitle: "" -metaDescription: "" +title: 'Data modeling' +metaTitle: '' +metaDescription: '' --- ## What is data modeling? @@ -94,7 +94,7 @@ Notice how the `User` model in both cases has the same properties as the `users` With this setup, you can retrieve records from the `users` table and store them instances of your `User` type. The following example code snippet uses [`pg`](https://node-postgres.com/) as the driver for PostgreSQL and creates a `User` instance based on the above defined JavaScript class: ```js -const resultRows = await client.query("SELECT * FROM users WHERE user_id = 1"); +const resultRows = await client.query('SELECT * FROM users WHERE user_id = 1'); const userData = resultRows[0]; const user = new User(userData.user_id, userData.name, userData.email, userData.isAdmin); // user = { @@ -133,7 +133,7 @@ User.init( }, isAdmin: Sequelize.BOOLEAN, }, - { sequelize, modelName: "user" } + { sequelize, modelName: 'user' } ); ``` diff --git a/content/02-understand-prisma/index.mdx b/content/02-understand-prisma/index.mdx index 52da02da2d..e09b159659 100644 --- a/content/02-understand-prisma/index.mdx +++ b/content/02-understand-prisma/index.mdx @@ -1,5 +1,5 @@ --- -title: "Understand Prisma" -metaTitle: "Understand Prisma" -metaDescription: "Understand Prisma" +title: 'Understand Prisma' +metaTitle: 'Understand Prisma' +metaDescription: 'Understand Prisma' --- diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx index cc68452de2..97fd74e8db 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/01-what-is-the-prisma-schema.mdx @@ -1,7 +1,7 @@ --- -title: "Prisma schema file" -metaTitle: "" -metaDescription: "" +title: 'Prisma schema file' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -152,7 +152,7 @@ When running any command that needs to access the database defined via the `data If you want environment variables to be evaluated at runtime, you need to load them manually in your application code, e.g. using [`dotenv`](https://github.com/motdotla/dotenv): ```ts -import * as dotenv from "dotenv"; +import * as dotenv from 'dotenv'; dotenv.config(); // load the environment variables console.log(`The connection URL is ${process.env.DATABASE_URL}`); diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx index 2701762e9d..c485b17a47 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/02-data-sources.mdx @@ -1,7 +1,7 @@ --- -title: "Connectors" -metaTitle: "" -metaDescription: "" +title: 'Connectors' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx index 19bf29a7fd..4a449452db 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/03-generators.mdx @@ -1,7 +1,7 @@ --- -title: "Generators" -metaTitle: "" -metaDescription: "" +title: 'Generators' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx index 41bd8269c7..6439e070e9 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/05-models.mdx @@ -1,7 +1,7 @@ --- -title: "Models" -metaTitle: "" -metaDescription: "" +title: 'Models' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -184,7 +184,7 @@ Here is an example illustrating the use of a `user` property from the Prisma Cli ```js const newUser = await prisma.user.create({ data: { - name: "Alice", + name: 'Alice', }, }); const allUsers = await prisma.user.findMany(); diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx index 1837d1556a..557a4591ca 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/06-relations.mdx @@ -1,7 +1,7 @@ --- -title: "Relations" -metaTitle: "" -metaDescription: "" +title: 'Relations' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx b/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx index b0faddb77a..d439c38c43 100644 --- a/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-schema/index.mdx @@ -1,6 +1,6 @@ --- -title: "Schema" -metaTitle: "" -metaDescription: "" +title: 'Schema' +metaTitle: '' +metaDescription: '' experimental: true --- diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx index 8a9dd1a5f2..9b6492c834 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-generating-prisma-client.mdx @@ -1,7 +1,7 @@ --- -title: "Generating Prisma Client" -metaTitle: "" -metaDescription: "" +title: 'Generating Prisma Client' +metaTitle: '' +metaDescription: '' --- This page explains how to generate Prisma Client. Generating Prisma Client requires the Prisma CLI installed on your machine (learn more [here]()). @@ -36,7 +36,7 @@ Note also that `prisma generate` is _automatically_ invoked when you're installi Once generated, you can import and instantiate Prisma Client in your code as follows: ```js -import { PrismaClient } from "@prisma/client"; +import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); // use `prisma` in your application to read and write data in your DB @@ -45,7 +45,7 @@ const prisma = new PrismaClient(); or ```js -const { PrismaClient } = require("@prisma/client"); +const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); // use `prisma` in your application to read and write data in your DB @@ -121,7 +121,7 @@ After running `prisma generate` for that schema file, the Prisma Client package By generating Prisma Client into `node_modules/@prisma/client`, you can import it and instantiate it in your code as follows: ```js -import { PrismaClient } from "@prisma/client"; +import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); @@ -131,7 +131,7 @@ const prisma = new PrismaClient(); or ```js -const { PrismaClient } = require("@prisma/client"); +const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx index 76ca9bcde7..af7006ed8f 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-configuring-the-prisma-client-api.mdx @@ -1,7 +1,7 @@ --- -title: "Configuring the Prisma Client API" -metaTitle: "" -metaDescription: "" +title: 'Configuring the Prisma Client API' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -150,11 +150,11 @@ The current naming of relation fields can also lead to confusion in the Prisma C // Nested writes const profile = await prisma.profiles.create({ data: { - bio: "Hello World", + bio: 'Hello World', user_id: { create: { - name: "Alice", - email: "alice@prisma.io", + name: 'Alice', + email: 'alice@prisma.io', }, }, }, @@ -222,11 +222,11 @@ With these changes, you're now adhering to Prisma's naming conventions and the g // Nested writess const profile = await prisma.profile.create({ data: { - bio: "Hello World", + bio: 'Hello World', user: { create: { - name: "Alice", - email: "alice@prisma.io", + name: 'Alice', + email: 'alice@prisma.io', }, }, }, diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relations.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relations.mdx index 5717a0335a..28123d211c 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relations.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/04-relations.mdx @@ -1,7 +1,7 @@ --- -title: "Relations" -metaTitle: "" -metaDescription: "" +title: 'Relations' +metaTitle: '' +metaDescription: '' --- Coming soon 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx index 04480f144d..44a73193e1 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-field-selection.mdx @@ -1,7 +1,7 @@ --- -title: "Field selection" -metaTitle: "" -metaDescription: "" +title: 'Field selection' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -228,12 +228,12 @@ Since `findMany` returns an array of objects, `result` would now look as follows ```js [ { - email: "alice@prisma.io", - role: "ADMIN", + email: 'alice@prisma.io', + role: 'ADMIN', }, { - email: "bob@prisma.io", - role: "USER", + email: 'bob@prisma.io', + role: 'USER', }, ]; ``` @@ -261,15 +261,15 @@ In this case, the result might look as follow: [ { id: 1, - name: "Alice", + name: 'Alice', posts: [ - { id: 1, title: "Hello World" }, - { id: 2, title: "Bye bye" }, + { id: 1, title: 'Hello World' }, + { id: 2, title: 'Bye bye' }, ], }, { id: 2, - name: "Bob", + name: 'Bob', posts: [], }, ]; @@ -297,30 +297,30 @@ This would result in the following structure for the `result` object: [ { id: 1, - name: "Alice", + name: 'Alice', posts: [ { id: 1, - title: "Hello World", + title: 'Hello World', published: true, author: { id: 1, - name: "Alice", - email: "alice@prisma.io", - role: "ADMIN", + name: 'Alice', + email: 'alice@prisma.io', + role: 'ADMIN', coinflips: [true, false], profileViews: 0, }, }, { id: 2, - title: "Bye bye", + title: 'Bye bye', published: false, author: { id: 1, - name: "Alice", - email: "alice@prisma.io", - role: "USER", + name: 'Alice', + email: 'alice@prisma.io', + role: 'USER', coinflips: [], profileViews: 0, }, diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx index 60fda8d5b4..8027e4310a 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-raw-database-access.mdx @@ -1,7 +1,7 @@ --- -title: "Raw database access" -metaTitle: "" -metaDescription: "" +title: 'Raw database access' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -9,15 +9,15 @@ metaDescription: "" You can send raw SQL queries to your database using the `raw` function that's exposed by your `PrismaClient` instance. It returns the query results as plain old JavaScript objects: ```ts -const result = await prisma.raw("SELECT * FROM User;"); +const result = await prisma.raw('SELECT * FROM User;'); ``` `result` is an array where each object corresponds to a retrieved database record: ```js [ - { id: 1, email: "sarah@prisma.io", name: "Sarah" }, - { id: 2, email: "alice@prisma.io", name: "Alice" }, + { id: 1, email: 'sarah@prisma.io', name: 'Sarah' }, + { id: 2, email: 'alice@prisma.io', name: 'Alice' }, ]; ``` @@ -50,9 +50,9 @@ The return type of `raw` is a `Promise` for the [generic](https://www.typescript ```ts // import the generated `User` type from the `@prisma/client` module -import { User } from "@prisma/client"; +import { User } from '@prisma/client'; -const result = await prisma.raw("SELECT * FROM User;"); +const result = await prisma.raw('SELECT * FROM User;'); // result is of type: `User[]` ``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx index 66b60e77aa..ecc9812f8d 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-connection-management.mdx @@ -1,7 +1,7 @@ --- -title: "Connection management" -metaTitle: "" -metaDescription: "" +title: 'Connection management' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx index 2d1c2a7247..24b96c25e9 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-generated-types.mdx @@ -1,7 +1,7 @@ --- -title: "Advanced usage of generated types" -metaTitle: "" -metaDescription: "" +title: 'Advanced usage of generated types' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -75,7 +75,7 @@ type UserPersonalData = { While this is certainly feasible, this approach increases the maintenance burden upon changes to the Prisma schema as you need to manually maintain the types. A cleaner solution to this is to use the `UserGetIncludePayload` and `UserGetSelectPayload` types that are generated and exposed by Prisma Client: ```ts -import { UserGetIncludePayload, UserGetSelectPayload } from "@prisma/client"; +import { UserGetIncludePayload, UserGetSelectPayload } from '@prisma/client'; // Define a type that includes the relation to `Post` type UserWithPosts = UserGetIncludePayload<{ @@ -130,7 +130,7 @@ const usersWithPosts: UsersWithPosts = await getUsersWithPosts(); With the `PromiseReturnType` that is exposed by Prisma Client, you can solve this more elegantly: ```ts -import { PromiseReturnType } from "@prisma/client"; +import { PromiseReturnType } from '@prisma/client'; type UsersWithPosts = PromiseReturnType; ``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx index 0986b87565..b10e8b8086 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-filtering.mdx @@ -1,7 +1,7 @@ --- -title: "Filtering" -metaTitle: "" -metaDescription: "" +title: 'Filtering' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx index a166e1e8e7..bf64182f67 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/10-ordering.mdx @@ -1,7 +1,7 @@ --- -title: "Ordering" -metaTitle: "" -metaDescription: "" +title: 'Ordering' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx index a38750d215..e266faef0d 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/11-pagination.mdx @@ -1,7 +1,7 @@ --- -title: "Pagination" -metaTitle: "" -metaDescription: "" +title: 'Pagination' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/13-debugging.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/13-debugging.mdx index e321d65a44..1d1770ae5d 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/13-debugging.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/13-debugging.mdx @@ -1,7 +1,7 @@ --- -title: "Debugging" -metaTitle: "" -metaDescription: "" +title: 'Debugging' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx index 187e7734f6..187d182ead 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/14-error-formatting.mdx @@ -1,7 +1,7 @@ --- -title: "Error formatting" -metaTitle: "" -metaDescription: "" +title: 'Error formatting' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -41,7 +41,7 @@ It can be used like so: ```ts const prisma = new PrismaClient({ - errorFormat: "minimal", + errorFormat: 'minimal', }); ``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx index 210570c5fe..df916a1a71 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-transactions.mdx @@ -1,7 +1,7 @@ --- -title: "Transactions" -metaTitle: "" -metaDescription: "" +title: 'Transactions' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -36,11 +36,11 @@ Here are examples for nested writes in the Prisma Client API: // single transaction const newUser: User = await prisma.user.create({ data: { - email: "alice@prisma.io", + email: 'alice@prisma.io', posts: { create: [ - { title: "Join the Prisma Slack on https://slack.prisma.io" }, - { title: "Follow @prisma on Twitter" }, + { title: 'Join the Prisma Slack on https://slack.prisma.io' }, + { title: 'Follow @prisma on Twitter' }, ], }, }, @@ -53,7 +53,7 @@ const updatedPost: Post = await prisma.post.update({ where: { id: 42 }, data: { author: { - connect: { email: "alice@prisma.io" }, + connect: { email: 'alice@prisma.io' }, }, }, }); @@ -87,7 +87,7 @@ The second use case of longer-running transactions where operations can depend o ```ts prisma.transaction(async tx => { const user = await tx.users.create({ - data: { email: "alice@prisma.io" }, + data: { email: 'alice@prisma.io' }, }); const order = await tx.orders.create({ data: { diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-deployment.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-deployment.mdx index d213e5cbeb..a51939d812 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-deployment.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-deployment.mdx @@ -1,7 +1,7 @@ --- -title: "Deployment" -metaTitle: "" -metaDescription: "" +title: 'Deployment' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx index ead6beeb22..5a342c4f12 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/17-query-engine.mdx @@ -1,7 +1,7 @@ --- -title: "Query engine" -metaTitle: "" -metaDescription: "" +title: 'Query engine' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -72,7 +72,7 @@ You can also get more visibility into the SQL queries that are generated by the ```ts const prisma = new PrismaClient({ - log: ["query"], + log: ['query'], }); ``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-usage-with-module-bundlers.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-usage-with-module-bundlers.mdx index de7282c61d..1fc8d6be4a 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-usage-with-module-bundlers.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-usage-with-module-bundlers.mdx @@ -1,7 +1,7 @@ --- -title: "Usage with module bundlers" -metaTitle: "" -metaDescription: "" +title: 'Usage with module bundlers' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx index 1f67de3355..7f7b9f9cb8 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/19-api.mdx @@ -1,7 +1,7 @@ --- -title: "Prisma Client API" -metaTitle: "" -metaDescription: "" +title: 'Prisma Client API' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx index 7ca9819493..219b2a8090 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/index.mdx @@ -1,5 +1,5 @@ --- -title: "Prisma Client" -metaTitle: "" -metaDescription: "" +title: 'Prisma Client' +metaTitle: '' +metaDescription: '' --- diff --git a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx index 2ba2096d40..db51c81e68 100644 --- a/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/03-prisma-migrate/index.mdx @@ -1,6 +1,6 @@ --- -title: "Prisma Migrate" -metaTitle: "" -metaDescription: "" +title: 'Prisma Migrate' +metaTitle: '' +metaDescription: '' experimental: true --- diff --git a/content/03-reference/01-tools-and-interfaces/04-introspection.mdx b/content/03-reference/01-tools-and-interfaces/04-introspection.mdx index 88391c6786..7a523aee2e 100644 --- a/content/03-reference/01-tools-and-interfaces/04-introspection.mdx +++ b/content/03-reference/01-tools-and-interfaces/04-introspection.mdx @@ -1,7 +1,7 @@ --- -title: "Introspection" -metaTitle: "" -metaDescription: "" +title: 'Introspection' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx index 3161a91dff..c1a826c949 100644 --- a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx +++ b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/01-installation.mdx @@ -1,7 +1,7 @@ --- -title: "Installation" -metaTitle: "" -metaDescription: "" +title: 'Installation' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx index 9a9043b19d..bef97e1d64 100644 --- a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx +++ b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/02-command-reference.mdx @@ -1,7 +1,7 @@ --- -title: "CLI command reference" -metaTitle: "" -metaDescription: "" +title: 'CLI command reference' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx index ed81f6243a..d52a501bca 100644 --- a/content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/05-prisma-cli/index.mdx @@ -1,5 +1,5 @@ --- -title: "Prisma CLI" -metaTitle: "" -metaDescription: "" +title: 'Prisma CLI' +metaTitle: '' +metaDescription: '' --- diff --git a/content/03-reference/01-tools-and-interfaces/index.mdx b/content/03-reference/01-tools-and-interfaces/index.mdx index 02ed00f97c..22970e603b 100644 --- a/content/03-reference/01-tools-and-interfaces/index.mdx +++ b/content/03-reference/01-tools-and-interfaces/index.mdx @@ -1,6 +1,6 @@ --- -title: "Tools & Interfaces" -metaTitle: "" -metaDescription: "" +title: 'Tools & Interfaces' +metaTitle: '' +metaDescription: '' staticLink: true --- diff --git a/content/03-reference/02-database-connectors/01-postgresql.mdx b/content/03-reference/02-database-connectors/01-postgresql.mdx index ddd5726d7d..e73dd09535 100644 --- a/content/03-reference/02-database-connectors/01-postgresql.mdx +++ b/content/03-reference/02-database-connectors/01-postgresql.mdx @@ -1,7 +1,7 @@ --- -title: "PostgreSQL" -metaTitle: "" -metaDescription: "" +title: 'PostgreSQL' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/03-reference/02-database-connectors/02-mysql.mdx b/content/03-reference/02-database-connectors/02-mysql.mdx index 67d54a5daf..0bb0450394 100644 --- a/content/03-reference/02-database-connectors/02-mysql.mdx +++ b/content/03-reference/02-database-connectors/02-mysql.mdx @@ -1,7 +1,7 @@ --- -title: "MySQL" -metaTitle: "" -metaDescription: "" +title: 'MySQL' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/03-reference/02-database-connectors/03-sqlite.mdx b/content/03-reference/02-database-connectors/03-sqlite.mdx index 6c5df7a9ed..38dae3a2de 100644 --- a/content/03-reference/02-database-connectors/03-sqlite.mdx +++ b/content/03-reference/02-database-connectors/03-sqlite.mdx @@ -1,7 +1,7 @@ --- -title: "SQLite" -metaTitle: "" -metaDescription: "" +title: 'SQLite' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/03-reference/02-database-connectors/index.mdx b/content/03-reference/02-database-connectors/index.mdx index 7f5f15f393..eb98384b30 100644 --- a/content/03-reference/02-database-connectors/index.mdx +++ b/content/03-reference/02-database-connectors/index.mdx @@ -1,6 +1,6 @@ --- -title: "Database connectors" -metaTitle: "" -metaDescription: "" +title: 'Database connectors' +metaTitle: '' +metaDescription: '' staticLink: true --- diff --git a/content/03-reference/03-more/01-editor-setup.mdx b/content/03-reference/03-more/01-editor-setup.mdx index d4abe277fd..f19c0a7250 100644 --- a/content/03-reference/03-more/01-editor-setup.mdx +++ b/content/03-reference/03-more/01-editor-setup.mdx @@ -1,7 +1,7 @@ --- -title: "Editor setup" -metaTitle: "" -metaDescription: "" +title: 'Editor setup' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/03-reference/03-more/02-telemetry.mdx b/content/03-reference/03-more/02-telemetry.mdx index ac69c2d4cd..f2822f2a18 100644 --- a/content/03-reference/03-more/02-telemetry.mdx +++ b/content/03-reference/03-more/02-telemetry.mdx @@ -1,7 +1,7 @@ --- -title: "Telemetry" -metaTitle: "" -metaDescription: "" +title: 'Telemetry' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/03-reference/03-more/index.mdx b/content/03-reference/03-more/index.mdx index c63f53691e..101a34fbce 100644 --- a/content/03-reference/03-more/index.mdx +++ b/content/03-reference/03-more/index.mdx @@ -1,6 +1,6 @@ --- -title: "More" -metaTitle: "" -metaDescription: "" +title: 'More' +metaTitle: '' +metaDescription: '' staticLink: true --- diff --git a/content/03-reference/index.mdx b/content/03-reference/index.mdx index c4c60d2c77..c8580c13f1 100644 --- a/content/03-reference/index.mdx +++ b/content/03-reference/index.mdx @@ -1,5 +1,5 @@ --- -title: "Reference" -metaTitle: "Reference" -metaDescription: "Reference" +title: 'Reference' +metaTitle: 'Reference' +metaDescription: 'Reference' --- diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx index cd0bf063cf..1760655b22 100644 --- a/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/01-postgresql.mdx @@ -1,7 +1,7 @@ --- -title: "Setting up a database (PostgreSQL)" -metaTitle: "" -metaDescription: "" +title: 'Setting up a database (PostgreSQL)' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx index a5f54160cf..56f35734a8 100644 --- a/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/02-mysql.mdx @@ -1,7 +1,7 @@ --- -title: "Setting up a database (MySQL)" -metaTitle: "" -metaDescription: "" +title: 'Setting up a database (MySQL)' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/03-sqlite.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/03-sqlite.mdx index f3c247e17f..a09e715313 100644 --- a/content/04-guides/01-database-workflows/01-setting-up-a-database/03-sqlite.mdx +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/03-sqlite.mdx @@ -1,7 +1,7 @@ --- -title: "Setting up a database (SQLite)" -metaTitle: "" -metaDescription: "" +title: 'Setting up a database (SQLite)' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx b/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx index aef141b55c..848860f9ca 100644 --- a/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx +++ b/content/04-guides/01-database-workflows/01-setting-up-a-database/index.mdx @@ -1,4 +1,4 @@ --- -title: "Setting up a database" -metaTitle: "" +title: 'Setting up a database' +metaTitle: '' --- diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx index c2e4c62161..8bbd84cd25 100644 --- a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/01-postgresql.mdx @@ -1,7 +1,7 @@ --- -title: "Importing and exporting data (PostgreSQL)" -metaTitle: "" -metaDescription: "" +title: 'Importing and exporting data (PostgreSQL)' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx index e75b3de43f..2b13d14c4a 100644 --- a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/02-mysql.mdx @@ -1,7 +1,7 @@ --- -title: "Importing and exporting data (MySQL)" -metaTitle: "" -metaDescription: "" +title: 'Importing and exporting data (MySQL)' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/03-sqlite.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/03-sqlite.mdx index 914a23d82f..838f74308d 100644 --- a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/03-sqlite.mdx +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/03-sqlite.mdx @@ -1,7 +1,7 @@ --- -title: "Importing and exporting data (SQLite)" -metaTitle: "" -metaDescription: "" +title: 'Importing and exporting data (SQLite)' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx index 3544559761..b013667942 100644 --- a/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx +++ b/content/04-guides/01-database-workflows/02-importing-and-exporting-data/index.mdx @@ -1,4 +1,4 @@ --- -title: "Importing and exporting data" -metaTitle: "" +title: 'Importing and exporting data' +metaTitle: '' --- diff --git a/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx b/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx index 47afcbc3ed..0dcbc719aa 100644 --- a/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/03-primary-keys/01-postgresql.mdx @@ -1,7 +1,7 @@ --- -title: "Primary keys (PostgreSQL)" -metaTitle: "" -metaDescription: "" +title: 'Primary keys (PostgreSQL)' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx b/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx index fe00ec33ce..237179f2f1 100644 --- a/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/03-primary-keys/02-mysql.mdx @@ -1,7 +1,7 @@ --- -title: "Primary keys (MySQL)" -metaTitle: "" -metaDescription: "" +title: 'Primary keys (MySQL)' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/04-guides/01-database-workflows/03-primary-keys/03-sqlite.mdx b/content/04-guides/01-database-workflows/03-primary-keys/03-sqlite.mdx index 2cabb744b5..e2e6a37e1d 100644 --- a/content/04-guides/01-database-workflows/03-primary-keys/03-sqlite.mdx +++ b/content/04-guides/01-database-workflows/03-primary-keys/03-sqlite.mdx @@ -1,7 +1,7 @@ --- -title: "Primary keys (SQLite)" -metaTitle: "" -metaDescription: "" +title: 'Primary keys (SQLite)' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/04-guides/01-database-workflows/03-primary-keys/index.mdx b/content/04-guides/01-database-workflows/03-primary-keys/index.mdx index ed56855a19..428ab02a64 100644 --- a/content/04-guides/01-database-workflows/03-primary-keys/index.mdx +++ b/content/04-guides/01-database-workflows/03-primary-keys/index.mdx @@ -1,4 +1,4 @@ --- -title: "Primary keys" -metaTitle: "" +title: 'Primary keys' +metaTitle: '' --- diff --git a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx index 427bc21ada..025cdb73ab 100644 --- a/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx +++ b/content/04-guides/01-database-workflows/04-unique-constraints-and-indexes/index.mdx @@ -1,4 +1,4 @@ --- -title: "Unique constraints and indexes" -metaTitle: "" +title: 'Unique constraints and indexes' +metaTitle: '' --- diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx index 0bd230df68..ba5e8d5f03 100644 --- a/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx @@ -1,7 +1,7 @@ --- -title: "Foreign keys / Relations (MySQL)" -metaTitle: "" -metaDescription: "" +title: 'Foreign keys / Relations (MySQL)' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -211,17 +211,17 @@ Now you can use Prisma Client to send database queries in Node.js. Create a new file called `index.js` and add the following code to it: ```js -const { PrismaClient } = require("@prisma/client"); +const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); async function main() { const userWithPost = await prisma.user.create({ data: { - name: "Alice", + name: 'Alice', post: { create: { - title: "Hello World from Alice", + title: 'Hello World from Alice', }, }, }, @@ -233,11 +233,11 @@ async function main() { const anotherUserWithPost = await prisma.anotherUser.create({ data: { - firstName: "Bob", - lastName: "Smith", + firstName: 'Bob', + lastName: 'Smith', anotherPost: { create: { - title: "Hello World from Bob", + title: 'Hello World from Bob', }, }, }, diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx index 0891f607e0..9af3d5213b 100644 --- a/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx +++ b/content/04-guides/01-database-workflows/05-foreign-keys/index.mdx @@ -1,4 +1,4 @@ --- -title: "Foreign keys" -metaTitle: "" +title: 'Foreign keys' +metaTitle: '' --- diff --git a/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx b/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx index 1c2708b09a..56a697e95b 100644 --- a/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx +++ b/content/04-guides/01-database-workflows/06-cascading-deletes/index.mdx @@ -1,4 +1,4 @@ --- -title: "Cascading deletes" -metaTitle: "" +title: 'Cascading deletes' +metaTitle: '' --- diff --git a/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx b/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx index 60ee70c43c..dd78ac0de1 100644 --- a/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx @@ -1,7 +1,7 @@ --- -title: "Data validation with CHECK constraints (PostgreSQL)" -metaTitle: "" -metaDescription: "" +title: 'Data validation with CHECK constraints (PostgreSQL)' +metaTitle: '' +metaDescription: '' --- ## Overview @@ -344,7 +344,7 @@ Now you can use Prisma Client to send database queries in Node.js. Create a new file called `index.js` and add the following code to it: ```js -const { PrismaClient } = require("@prisma/client"); +const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); @@ -379,7 +379,7 @@ ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error To validate the multi-column check constraint, replace the code in `index.js` with the following: ```js -const { PrismaClient } = require("@prisma/client"); +const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); @@ -415,7 +415,7 @@ ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error Finally, modify the script to include multiple check constraint violations: ```js -const { PrismaClient } = require("@prisma/client"); +const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); @@ -423,7 +423,7 @@ async function main() { const newProduct = await prisma.secondtolastproduct.create({ data: { tags: { - set: ["wrongtag"], + set: ['wrongtag'], }, price: 90.0, reducedprice: 100.0, diff --git a/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx b/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx index f7bc09159e..3bbb1a50ed 100644 --- a/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/07-data-validation/02-mysql.mdx @@ -1,7 +1,7 @@ --- -title: "Data validation with CHECK constraints (MySQL)" -metaTitle: "" -metaDescription: "" +title: 'Data validation with CHECK constraints (MySQL)' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/04-guides/01-database-workflows/07-data-validation/03-sqlite.mdx b/content/04-guides/01-database-workflows/07-data-validation/03-sqlite.mdx index e2cc0be6dd..b85dc312a9 100644 --- a/content/04-guides/01-database-workflows/07-data-validation/03-sqlite.mdx +++ b/content/04-guides/01-database-workflows/07-data-validation/03-sqlite.mdx @@ -1,7 +1,7 @@ --- -title: "Data validation with CHECK constraints (SQLite)" -metaTitle: "" -metaDescription: "" +title: 'Data validation with CHECK constraints (SQLite)' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/04-guides/01-database-workflows/07-data-validation/index.mdx b/content/04-guides/01-database-workflows/07-data-validation/index.mdx index f0d25c081a..d532994bde 100644 --- a/content/04-guides/01-database-workflows/07-data-validation/index.mdx +++ b/content/04-guides/01-database-workflows/07-data-validation/index.mdx @@ -1,4 +1,4 @@ --- -title: "Data validation" -metaTitle: "" +title: 'Data validation' +metaTitle: '' --- diff --git a/content/04-guides/01-database-workflows/index.mdx b/content/04-guides/01-database-workflows/index.mdx index 2b10eb4461..c55abe42c9 100644 --- a/content/04-guides/01-database-workflows/index.mdx +++ b/content/04-guides/01-database-workflows/index.mdx @@ -1,5 +1,5 @@ --- -title: "Database workflows" -metaTitle: "Guides" +title: 'Database workflows' +metaTitle: 'Guides' staticLink: true --- diff --git a/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx b/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx index 49a874d306..e653317eab 100644 --- a/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx +++ b/content/04-guides/02-deployment/01-deploying-to-zeit-now.mdx @@ -1,7 +1,7 @@ --- -title: "Deploying to ZEIT Now" -metaTitle: "" -metaDescription: "" +title: 'Deploying to ZEIT Now' +metaTitle: '' +metaDescription: '' --- ## Overview diff --git a/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx b/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx index 388005d51f..81b1274717 100644 --- a/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx +++ b/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx @@ -1,7 +1,7 @@ --- -title: "Deploying to AWS Lambda" -metaTitle: "" -metaDescription: "" +title: 'Deploying to AWS Lambda' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/04-guides/02-deployment/03-deploying-to-heroku.mdx b/content/04-guides/02-deployment/03-deploying-to-heroku.mdx index d48641389d..90440bbc9d 100644 --- a/content/04-guides/02-deployment/03-deploying-to-heroku.mdx +++ b/content/04-guides/02-deployment/03-deploying-to-heroku.mdx @@ -1,7 +1,7 @@ --- -title: "Deploying to Heroku" -metaTitle: "" -metaDescription: "" +title: 'Deploying to Heroku' +metaTitle: '' +metaDescription: '' --- Coming 🔜 diff --git a/content/04-guides/02-deployment/index.mdx b/content/04-guides/02-deployment/index.mdx index 09054af8f6..74c2f47b72 100644 --- a/content/04-guides/02-deployment/index.mdx +++ b/content/04-guides/02-deployment/index.mdx @@ -1,6 +1,6 @@ --- -title: "Deployment" -metaTitle: "" -metaDescription: "" +title: 'Deployment' +metaTitle: '' +metaDescription: '' staticLink: true --- diff --git a/content/04-guides/index.mdx b/content/04-guides/index.mdx index c268a140da..d470f68d16 100644 --- a/content/04-guides/index.mdx +++ b/content/04-guides/index.mdx @@ -1,5 +1,5 @@ --- -title: "Guides" -metaTitle: "Guides" -metaDescription: "Guides" +title: 'Guides' +metaTitle: 'Guides' +metaDescription: 'Guides' --- diff --git a/src/components/customMdx/code.tsx b/src/components/customMdx/code.tsx index 9fd8759e6e..3eee865817 100644 --- a/src/components/customMdx/code.tsx +++ b/src/components/customMdx/code.tsx @@ -1,5 +1,5 @@ -import React from "react"; -import styled from "styled-components"; +import React from 'react'; +import styled from 'styled-components'; interface CodeProps { languages?: string[]; @@ -20,7 +20,7 @@ const CodeBlock = ({ languages, children, ...props }: CodeBlockProps) => { const setCurrentActive = () => setActiveIndex(index); return (
    { {copied && ( -
    +
    Copied
    )} @@ -34,7 +34,7 @@ const CopyButton = ({ text, children, ...props }: CopyButtonProps) => { export default CopyButton; const CopyComponent = styled.div` - font-family: "Open Sans"; + font-family: 'Open Sans'; & { position: relative; cursor: pointer; diff --git a/src/components/customMdx/index.tsx b/src/components/customMdx/index.tsx index 92308a21c8..c94910390d 100644 --- a/src/components/customMdx/index.tsx +++ b/src/components/customMdx/index.tsx @@ -1,25 +1,25 @@ -import React from "react"; -import CodeBlock from "./code"; -import Pre from "./pre"; +import React from 'react'; +import CodeBlock from './code'; +import Pre from './pre'; export default { h1: (props: any) => ( -

    +

    ), h2: (props: any) => ( -

    +

    ), h3: (props: any) => ( -

    +

    ), h4: (props: any) => ( -

    +

    ), h5: (props: any) => ( -

    +
    ), h6: (props: any) => ( -
    +
    ), p: (props: any) =>

    , ul: (props: any) =>