Exploring Directives in Prisma

Joshua Hall

Besides the many hours of grunt work that Prisma saves by generating our CRUD operations for us, it also gives us access to a few other features that’ll save us even more time and give us more sophisticated control over our data structure. In this article, we’re going to be exploring some of the most common directives you’ll be using in your schemas.

Prerequisites

Were going to be doing things that will help enhance our schemas, so you can refresh on the basics here.

You’re also going to need a basic Prisma container setup with a database of your choice. You can either check out this article or setting up Prisma with Docker, or you can just copy this repo and deploy it onto a new container.

Unique Directive

Imagine we have an app and we want to add a new user while securing our app against users with the same email. Instead of having to manually send a query and check if a match already exists before saving something to the database, Prisma gives us a handy @unique directive that’ll handle it for us. ID’s have their own special equivalent, just called @id, which does basically the same thing.

type User {
  id: ID! @id
  name: String!
  email: String! @unique 
  age: Int!
}

With that we can have a condition to tell the user it wasn’t available when a mutation fails.

Default Directive

Many times we obviously don’t want to make the user fill out everything their account may need, like whether they’re a basic user or an admin. It would be very useful to be able to add default values for those types of data.

The simplest way of handling that would be to just use the @default directive to add a placeholder value.

type User {
  id: ID! @id
  name: String!
  email: String! @unique
  type: UserType! @default(value: USER)
}

enum UserType {
  USER 
  ADMIN
}

Rename Directive

Our data structures aren’t going to be built once and used forever, we eventually going to need to change some things around. While Prisma is pretty good about adding and removing new properties and types, it can have some problems when you want to rename a type that already has saved data reliant on it.

@rename is a temporary directive, meaning that we just use it once, redeploy our schema, then remove it from datamodel.graphql.

type User {
  id: ID! @id
  name: String!
  email: String!
  posts: [Content!]
}

type Content {
  id: ID! @id 
  title: String! @unique 
  body: String! 
  author: User!
}

Content is a pretty vague name, let’s use @rename to change it to something a bit more explicit.

type User {
  id: ID! @id
  name: String!
  email: String!
  posts: [Content!]
}

type Post @rename(oldName: "Content") {
  id: ID! @id 
  title: String! @unique 
  body: String! 
  author: User!
}

Move into your prisma folder and redeploy your schema.

$ prisma deploy

Now you can safely remove @rename without messing up your data.

Relation Directive

The most useful and common thing you’ll be doing with directives is setting up relationships between your data types.

If we removed a product from our store, we would obviously want to remove every review for it from the database. If we were to delete the owner of that product we’d remove their products and the subsequent reviews. The problem is there needs to be a specific way of organizing this hierarchy, because we wouldn’t want to remove the user when their product or a review is removed.

The @relation directive solves this problem pretty elegantly, we just need to pass a name that will link the two types together and tell it what we want done onDelete, Either to stop or continue the deletions down the chain. CASCADE will delete the type on the other side of the chain, while SET_NULL will leave it.

type User {
  id: ID! @id
  name: String!
  selling: [Product!] @relation(name: "UserToProduct", onDelete: CASCADE)
}

type Product {
  id: ID! @id 
  name: String!
  seller: User! @relation(name: "UserToProduct", onDelete: SET_NULL)
  reviews: [Review!] @relation(name: "ProductToReview", onDelete: CASCADE)
}

type Review {
  id: ID! @id 
  author: User! 
  review: String!
  product: Product! @relation(name: "ProductToReview", onDelete: SET_NULL)
}

Closing Thoughts

There are a few more options that are worth checking out over in the official docs.

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#