Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save andyvauliln/3979613fd46cd694318685928e22c815 to your computer and use it in GitHub Desktop.

Select an option

Save andyvauliln/3979613fd46cd694318685928e22c815 to your computer and use it in GitHub Desktop.
Nexus + Prisma CheatSheet

Nexus + Prisma CheatSheet

Creating model in Prisma

First create generator and datasource entry in your .prisma file like below:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

Example 1:

model User {
  id         String    @id @default(cuid())   // ID type column whose default value is cuid
  createdAt  DateTime  @default(now())    // Date type column whose default value is current date and time
  modifiedAt DateTime  @default(now())    // Date type column whose default value is current date and time
  email      String    @unique    // String type column whose value must be unique
  name       String?    // String type column whose value is optional
}

Example 2:

model Question {
  id         String      @id @default(cuid())   // ID type column whose default value is cuid
  createdAt  DateTime    @default(now())    // Date type column whose default value is current date and time
  modifiedAt DateTime    @default(now())    // Date type column whose default value is current date and time
  text       String    // String type column
  options    String[]    // Column value should be a list of string
  answer     String    // String type column
  marks      Int         @default(0)    // Integer type column whose default value is null
  negativeMarking Boolean    @default(false)    // Boolean type value whose default value is false
}

Create relationship between Prisma models

It is very important to remember there is never a prisma model relationship. Relationships are always both sided.

Example 1: Many-to-Many relationship

model User {
  id         String    @id @default(cuid())
  createdAt  DateTime  @default(now())
  modifiedAt DateTime  @default(now())
  email      String    @unique
  projects   Project[]    // Model User has many relationship with Project model
  name       String?
}

model Project {
  id                     String    @id @default(cuid())
  createdAt              DateTime  @default(now())
  modifiedAt             DateTime  @default(now())
  users                  User[]    // Model Project has many relationship with User model
  name                   String
  slug                   String    @unique
  stripeCustomerId       String?   @unique
  stripeSubscriptionId   String?   @unique
  stripePriceId          String?
  stripeCurrentPeriodEnd DateTime?
}

Example 2: Many-to-One relationship

model TestPaper {
  id              String     @id @default(cuid())
  createdAt       DateTime   @default(now())
  modifiedAt      DateTime   @default(now())
  title           String
  description     String
  expireInDays    Int        @default(0)
  maxAttempt      Int        @default(1)
  negativeMarking Boolean    @default(false)
  totalTime       Int        @default(0)
  results         Result[]    // Model TestPaper has many relationship on Result model
}

model Result {
  id         String    @id @default(cuid())
  createdAt  DateTime  @default(now())
  modifiedAt DateTime  @default(now())
  testId     String
  test       TestPaper @relation(fields: [testId], references: [id])    // Model Result has one relationship with TestPaper model
  score      Int
}

Example 3: Mixed relationships

model User {
  id         String    @id @default(cuid())
  createdAt  DateTime  @default(now())
  modifiedAt DateTime  @default(now())
  email      String    @unique
  projects   Project[]
  name       String?
  testsTaken Result[]
}

model Project {
  id                     String    @id @default(cuid())
  createdAt              DateTime  @default(now())
  modifiedAt             DateTime  @default(now())
  users                  User[]
  name                   String
  slug                   String    @unique
  stripeCustomerId       String?   @unique
  stripeSubscriptionId   String?   @unique
  stripePriceId          String?
  stripeCurrentPeriodEnd DateTime?
  BigNum                 BigInt
}

model Question {
  id         String      @id @default(cuid())
  createdAt  DateTime    @default(now())
  modifiedAt DateTime    @default(now())
  text       String
  options    String[]
  answer     String
  marks      Int         @default(0)
  papers     TestPaper[]
}

model TestPaper {
  id              String     @id @default(autoincriment())
  createdAt       DateTime   @default(now())
  modifiedAt      DateTime   @default(now())
  title           String
  description     String
  expireInDays    Int        @default(0)
  maxAttempt      Int        @default(1)
  questions       Question[]
  negativeMarking Boolean    @default(false)
  totalTime       Int        @default(0)
  results         Result[]
}

model Result {
  id         String    @id @default(autoincriment())
  createdAt  DateTime  @default(now())
  modifiedAt DateTime  @default(now())
  testId     String
  test       TestPaper @relation(fields: [testId], references: [id])
  userId     String
  user       User      @relation(fields: [userId], references: [id])
  answers    String[]
  score      Int
}

Create model with Nexus

Example 1:

/* eslint-disable no-return-await */
import {
  extendType,
  intArg,
  list,
  nonNull,
  objectType,
  stringArg,
} from "nexus";
import prisma from "../../db/prisma";

const Question = objectType({
  name: "Question",
  definition(t) {
    t.nonNull.string("id"); // non-null string column with name `id`
    t.nonNull.string("text"); // non-null string column with name `text`
    t.nonNull.list.nonNull.string("options"); // non-nullable list of string column with name `options`
    t.nonNull.string("answer"); // non-null string column with name `answer`
    t.nonNull.int("marks"); // non-null integer column with name `marks`
    t.nullable.int("expireInDays"); // nullable integer type column
    t.nullable.int("maxAttempt"); // nullable integer type column
    t.nullable.boolean("negativeMarking"); // nullable boolean type column
    t.nullable.int("totalTime"); // nullable integer type column
  },
});

CLI results

Providers

(postgresql, mysql, sqlite, sqlserver, mongodb, cockroachdb)

Usage

$ prisma [command]

Commands

        init   Setup Prisma for your app
    generate   Generate artifacts (e.g. Prisma Client)
          db   Manage your database schema and lifecycle
     migrate   Migrate your database
      studio   Browse your data with Prisma Studio
      format   Format your schema

Flags

 --preview-feature   Run Preview Prisma commands

Examples

Setup a new Prisma project

prisma init --datasource-provider sqlite prisma init --url mysql://user:password@localhost:3306/mydb

Generate artifacts (e.g. Prisma Client)

$ prisma generate

Browse your data

$ prisma studio

Create migrations from your Prisma schema, apply them to the database, generate artifacts (e.g. Prisma Client)

$ prisma migrate dev

Pull the schema from an existing database, updating the Prisma schema

$ prisma db pull

Push the Prisma schema state to the database

$ prisma db push

Generate

prisma generate prisma generate --schema=./alternative/schema.prisma prisma generate --watch import { PrismaClient } from '@prisma/client'

Format

prisma format

DB Pull

The db pull command connects to your database and adds Prisma models to your Prisma schema that reflect the current database schema.

prisma db pull prisma db pull --schema=./alternative/schema.prisma prisma db pull --print

db push

prisma db push --accept-data-loss npx prisma db push --schema=/tmp/schema.prisma

db seed

prisma db seed

db execute

This command applies a SQL script to the database without interacting with the Prisma migrations table. The script takes two inputs: the SQL script, which can be provided either on standard input or in a file the data source, which can either be the URL of the data source or the path to your Prisma schema file

prisma db execute --file ./script.sql --schema schema.prisma $ echo 'TRUNCATE TABLE dev;' | prisma db execute --stdin --url="$DATABASE_URL"

Migrate Dev

The migrate dev command updates your database using migrations during development and creates the database if it does not exist. prisma migrate dev --name init prisma migrate dev --create-only

Migrate Reset

This command deletes and recreates the database, or performs a 'soft reset' by removing all data, tables, indexes, and other artifacts prisma migrate reset

Migrate Deploy

The migrate deploy command applies all pending migrations, and creates the database if it does not exist. Primarily used in non-development environments. This command: prisma migrate deploy

Migrate Resolve

The migrate resolve command allows you to solve migration history issues in production by marking a failed migration as already applied (supports baselining) or rolled back.

prisma migrate resolve --applied 20201231000000_add_users_table prisma migrate resolve --rolled-back 20201231000000_add_users_table

Migrate Status

The prisma migrate status command looks up the migrations in /prisma/migrations/* folder and the entries in the _prisma_migrations table and compiles information about the state of the migrations in your database.

prisma migrate status

Migrate Diff

This command compares two database schema sources and outputs a description of a migration taking the first to the state of the second.

prisma migrate diff --from-... --to-... prisma migrate diff
--from-url "$DATABASE_URL" \ --to-url "postgresql://login:password@localhost:5432/db2" prisma migrate diff \ --from-url "$DATABASE_URL"
--to-migrations ./migrations
--script > script.sql

Studio

Start Studio on the default port and open a new browser tab to it

prisma studio --port 7777

Create model mutation in Nexus for modifying data in model

Example 1:

You must first define the model then create mutation for the model.

const mutations = extendType({
  type: "Mutation",
  definition: (t) => {
    t.nullable.field("createQuestion", {
      type: "Question",
      args: {
        text: nonNull(stringArg()),
        answer: nonNull(stringArg()),
        marks: nonNull(intArg()),
        options: nonNull(list(nonNull("String"))),
      },

      // Create data in model from args
      resolve: async (_, args, ctx) => {
        return await prisma.question.create({
          data: {
            text: args.text,
            answer: args.answer,
            marks: args.marks,
            options: args.options,
          },
        });
      },
    });

    t.nullable.field("updateQuestion", {
      type: "Question",
      args: {
        id: nonNull(stringArg()),
        text: nonNull(stringArg()),
        answer: nonNull(stringArg()),
        marks: nonNull(intArg()),
        options: nonNull(list(nonNull("String"))),
      },

      // Updates data in question model by ID
      resolve: async (_, args, ctx) => {
        return await prisma.question.update({
          where: { id: args.id },
          data: {
            text: args.text,
            answer: args.answer,
            marks: args.marks,
            options: args.options,
          },
        });
      },
    });
  },
});

Graphql mutation query for above mutation will look like below:

mutation CreateQuestion(
  $text: String!
  $answer: String!
  $marks: Int!
  $options: [String!]!
  $topicId: ID
) {
  createQuestion(
    text: $text
    answer: $answer
    marks: $marks
    options: $options
    topicId: $topicId
  ) {
    id
  }
}
mutation UpdateQuestion(
  $id: String!
  $text: String!
  $answer: String!
  $marks: Int!
  $options: [String!]!
) {
  updateQuestion(
    id: $id
    text: $text
    answer: $answer
    marks: $marks
    options: $options
  ) {
    id
  }
}

Create Nexus model query to get data from model

Example 1: Get data by id in argument

import {
  arg,
  booleanArg,
  extendType,
  intArg,
  list,
  nonNull,
  objectType,
  stringArg,
} from "nexus";

const queries = extendType({
  type: "Query",
  definition: (t) => {
    t.field("question", {
      type: "Question",
      args: {
        id: nonNull(stringArg()),
      },
      // Query data from question model by ID from args
      resolve: (_, { id }: any, ctx) => {
        return prisma.question.findUnique({
          where: {
            id,
          },
        });
      },
    });
  },
});

The GraphQuery query object for above will look like below:

query GetQuestion($id: String!) {
  question(id: $id) {
    id
    text
    options
    answer
    marks
  }
}

Here the question in query is same as name of field in our query definition.

Example 2: Get all data using query

const queries = extendType({
  type: "Query",
  definition: (t) => {
    // get all papers
    t.list.field("papers", {
      type: "TestPaper",
      resolve: (_root, _args, ctx) => {
        if (!ctx.user?.id) return null;
        return prisma.testPaper.findMany();
      },
    });
  },
});

The GraphQuery query object for above will look like below:

query GetPaperList {
  papers {
    id
    title
    description
    expireInDays
    maxAttempt
    negativeMarking
    totalTime
  }
}

Here the papers in query is same as name of field in our query definition.

Creating Nexus model column to connect with ID of other model

Example 1:

import {
  arg,
  booleanArg,
  extendType,
  intArg,
  list,
  nonNull,
  objectType,
  stringArg,
} from "nexus";
import prisma from "../../db/prisma";

const TestPaper = objectType({
  name: "TestPaper",
  definition(t) {
    t.nonNull.string("id");
    t.nonNull.string("title");
    t.nonNull.string("description");
    t.nullable.int("expireInDays");
    t.nullable.int("maxAttempt");
    t.nullable.boolean("negativeMarking");
    t.nullable.int("totalTime");

    // questions field will be of type question ID
    // which will then be resolved from question table records using ID. It will be a list of ID
    t.nonNull.list.nonNull.field("questions", {
      type: "Question",
      resolve: (parent, _, ctx) =>
        ctx.prisma.testPaper
          .findUnique({ where: { id: parent.id } })
          .questions(),
    });
  },
});

The prisma model for above model will look like below:

model TestPaper {
  id              String     @id @default(cuid())
  createdAt       DateTime   @default(now())
  modifiedAt      DateTime   @default(now())
  title           String
  description     String
  expireInDays    Int        @default(0)
  maxAttempt      Int        @default(1)
  questions       Question[]
  negativeMarking Boolean    @default(false)
  totalTime       Int        @default(0)
}

Example 2:

const Question = objectType({
  name: "Question",
  definition(t) {
    t.nonNull.string("id");
    t.nonNull.string("text");
    t.nonNull.list.nonNull.string("options");
    t.nonNull.string("answer");
    t.nonNull.int("marks");

    // topicId field will be of type topic ID
    // which will then be resolved from topic table records
    t.nonNull.field("topic", {
      type: "Topic",
      // eslint-disable-next-line max-len
      resolve: (parent: any, _: any, ctx: any) =>
        ctx.prisma.question.findUnique({ where: { id: parent.id } }).topic(),
    });
  },
});

The prisma model for above model will look like below:

model Question {
  id         String      @id @default(cuid())
  createdAt  DateTime    @default(now())
  modifiedAt DateTime    @default(now())
  text       String
  options    String[]
  answer     String
  marks      Int         @default(0)
  papers     TestPaper[]
  topicId    String
  topic      Topic       @relation(fields: [topicId], references: [id])
}

Nexus mutation of above model will look like below:

const mutations = extendType({
  type: "Mutation",
  definition: (t) => {
    t.nullable.field("createQuestion", {
      type: "Question",
      args: {
        text: nonNull(stringArg()),
        answer: nonNull(stringArg()),
        marks: nonNull(intArg()),
        options: nonNull(list(nonNull("String"))),

        // topic ID of type ID which links to topic in model
        topicId: arg({
          type: "ID",
        }),
      },
      resolve: async (_, args: any, ctx) => {
        if (!ctx.user?.id) return null;

        return await prisma.question.create({
          data: {
            text: args.text,
            answer: args.answer,
            marks: args.marks,
            options: args.options,
            topic: {
              connect: { id: args.topicId } || null,
            },
          },
        });
      },
    });

    t.nullable.field("updateQuestion", {
      type: "Question",
      args: {
        id: nonNull(stringArg()),
        text: nonNull(stringArg()),
        answer: nonNull(stringArg()),
        marks: nonNull(intArg()),
        options: nonNull(list(nonNull("String"))),
      },
      resolve: async (_, args, ctx) => {
        if (!ctx.user?.id) return null;

        return await prisma.question.update({
          where: { id: args.id },
          data: {
            text: args.text,
            answer: args.answer,
            marks: args.marks,
            options: args.options,
          },
        });
      },
    });
  },
});

Creating Nexus mutation with connection to other model ID

Example 1:

const mutations = extendType({
  type: "Mutation",
  definition: (t) => {
    t.nullable.field("createTestPaper", {
      type: "TestPaper",
      args: {
        title: nonNull(stringArg()),
        description: nonNull(stringArg()),
        expireInDays: intArg(),
        maxAttempt: intArg(),
        negativeMarking: booleanArg(),
        totalTime: intArg(),
        // Questions will contain any array of ID
        questions: arg({
          type: list("ID"),
        }),
      },
      resolve: async (_, args: any, ctx) => {
        if (!ctx.user?.id) return null;

        return await prisma.testPaper.create({
          data: {
            title: args.title,
            description: args.description,
            expireInDays: args.expireInDays || 0,
            maxAttempt: args.maxAttempt || 1,
            negativeMarking: args.negativeMarking || false,
            totalTime: args.totalTime || 0, // 0 = infinite time
            // connecting question ID list in args with question table records
            questions: {
              connect: args.questions.map((que) => ({ id: que })) || [],
            },
          },
        });
      },
    });
  },
});

Graphql mutation query for above mutation will look like below:

mutation CreateTestPaper(
  $title: String!
  $description: String!
  $expireInDays: Int
  $maxAttempt: Int
  $negativeMarking: Boolean
  $totalTime: Int
  $questions: [ID!]!
) {
  createTestPaper(
    title: $title
    description: $description
    expireInDays: $expireInDays
    maxAttempt: $maxAttempt
    negativeMarking: $negativeMarking
    totalTime: $totalTime
    questions: $questions
  ) {
    id
  }
}

Creating Nexus query for many-to-many relationship

Example 1: Get ID of data from other row in many-to-many relationship

Nexus object model for the data model:

const TestPaper = objectType({
  name: "TestPaper",
  definition(t) {
    t.nonNull.string("id");
    t.nonNull.string("title");
    t.nonNull.string("description");
    t.nullable.int("expireInDays");
    t.nullable.int("maxAttempt");
    t.nullable.boolean("negativeMarking");
    t.nullable.int("totalTime");

    // questions field will be of type question ID
    // which will then be resolved from question table records
    t.nonNull.list.nonNull.field("questions", {
      type: "Question",
      resolve: (parent, _, ctx) =>
        ctx.prisma.testPaper
          .findUnique({ where: { id: parent.id } })
          .questions(),
    });
  },
});
const queries = extendType({
  type: "Query",
  definition: (t) => {
    // get all papers
    t.list.field("papers", {
      type: "TestPaper",
      resolve: (_root, _args, ctx) => {
        if (!ctx.user?.id) return null;

        // Include questions in query response
        return prisma.testPaper.findMany({
          include: { questions: true },
        });
      },
    });

    // Get paper by ID with question
    t.field("paperWithQuestion", {
      type: "TestPaper",
      args: {
        id: nonNull(stringArg()),
      },
      resolve: (_, { id }: any, ctx) => {
        if (!ctx.user?.id) return null;

        // Include questions in query response
        return prisma.testPaper.findUnique({
          where: {
            id,
          },
          include: { questions: true },
        });
      },
    });
  },
});

Graphql query for above query object will look like below:

Return only question ID list with query response along with test paper details:

query GetPaperList {
  papers {
    id
    title
    description
    expireInDays
    maxAttempt
    negativeMarking
    totalTime
    questions {
      id
    }
  }
}

Return question info list with query response along with test paper details:

query GetPaperWithQuestion($id: String!) {
  paperWithQuestion(id: $id) {
    id
    title
    description
    expireInDays
    maxAttempt
    negativeMarking
    totalTime
    questions {
      id
      text
      options
      answer
      marks
    }
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment