The Future Is Here: Qwik Meets Prisma Innovatively
Tags: qwik, prisma, typescript, web
Published: 2023-08-17 18:14:45

If you're coming from PHP, you have Doctrine. From JAVA, you have Hibernate. In Javascript and TypeScript, we have Prisma that allows you to do Object Relational Mapping by providing a type-safe and intuitive query API to work with. The Prisma team, best known for their work on "GraphQL Yoga,”  introduced  Prisma 1 in  2018, which was a GraphQL data access layer for databases, but in 2019 the team decided to change the vision and deprioritize GraphQL to have a more general solution for databases to cover more use cases. So 2020 was the year of Prisma 2.0. The team announced on different dates of the year the three primary components Prisma Client, Prisma Migrate, and Prisma Studio.

## Prisma 2 Components

### Prisma Client

Writing SQL queries will not be the case in Prisma 2. Prisma Client provides us with built-in intuitive API calls, which make it simple for developers to manipulate the database and execute complex queries using only pre-defined functions. Prisma Client has multiple features:

- **Type-safety**: TypeScript is a type-safe programming language that ensures that we are using the data that we should use based on the defined types. Prisma client takes advantage of this because the generated TypeScript types are based on our database schema, so it will help us to catch errors at the compile time.
- **Intuitive API**: it abstracts complex SQL queries into simple and clear functions, which gives the developer the ability to focus on the logic of his application.
- **Performance**: Query batching is the key to having a great performance in Prisma Client. This feature enables Prisma to minimize the number of query requests made to the database by grouping queries and sending them as a single batched request to the database. The result of this is reducing the latency.

### Prisma Migrate

Prisma Migrate is a special feature of Prisma. Using only files that we call “migration files,” we can implement the process of creating, updating, and managing databases using SQL commands. Prisma Migrate has multiple features:

- **Prisma Schema**: it's the core of Prisma. It contains the information needed for our Database. It's a file “schema.prisma”, defined using Prisma Schema Language (PSL), used for migration file generation.
- **Migration Files**: these are the files responsible for keeping the history and the actual state of our Database. Prisma Migrate can detect the changes that we make in our Prisma scheme and generates migration files for that.
- **Migrate CLI**: it's a command-line interface that helps us to manage our migrations(create new migrations, apply existing ones, and also rollbacking).
- **Introspection**: it's a feature that allows us to do reverse engineering by generating a Prisma schema file based on an existing database

### Prisma Studio

Prisma Studio is a user-friendly Graphical User Interface that allows us to visualize and interact with our database. It supports multiple databases: PostgreSQL, MySQL, SQLite, and SQL Server. Prisma Studio has multiple features: 

- **Data Management**: it allows us to perform queries such (Create, Read, Update, and Delete), so with that, it will be easy to manipulate data using a graphical interface.
- **Real-time Data**: with Prisma Studio, we can visualize changes in real-time. If a change occurs in the Database, it is automatically displayed on the graphical interface.
- **Cross-platform Compatibility**: it's is available in multiple OSs Windows, macOS, and Linux, and also it has a web version that we can access via the browser that we use.

## Brief Introduction to Qwik

Qwik is a framework created by the creator of Angular, Miško Hevery, with a collaboration of Adam Bradley, who created Ionic, and Manu Almeida, who created Gin Framework.

Qwik, the HTML first framework’s philosophy is clear: make the fastest possible time-to-interactive (to do it faster by doing nothing).

The framework delays the invocation of the javascript as much as possible and invokes it only when it is needed. The focus is on the first load.

If you want to dive deep into Qwik, we already have an article about it:

{% embed https://dev.to/this-is-learning/qwik-the-post-modern-framework-3c5o %}

## Integrate Prisma to Qwik

### Prerequisites

To get started with Qwik locally, we need the following:

- [Node.js v16.8](https://nodejs.org/en/download/) or higher
- Your favorite IDE ([vscode](https://code.visualstudio.com/) recommended)

### App Creation

Using the Qwik CLI, we will start by starting a new Qwik Project:

Using the Qwik CLI, we will start by starting a new Qwik Project:

```bash
npm create qwik@latest
```

To run the server, we will need the following command:

```bash
npm start
```

On port 5173, we will have our application running. Now we will install Prisma:

```bash
npm run qwik add prisma
```

After installing Prisma, we will have a folder added in the root of our project:

![Prisma Folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v3rdocf79mpq8ft03nz1.png)

The core file where we will define our scheme is `schema.prisma`, in this tutorial, we will define a model named Company and another one named Employee, and we establish between them a relation of one-to-many, so a user can have one company and a company can have multiple employees, here is how we will implement it:

```tsx
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

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

datasource db {
  provider = "sqlite"
  url      = "file:./dev.db"
}

model Employee {
  id    Int     @id @default(autoincrement())
  email String  @unique
  company Company @relation(fields: [companyId], references: [id])
  companyId Int
  name  String
}

model Company {
  id    Int     @id @default(autoincrement())
  website String  @unique
  name  String
  descriptions String
  employees Employee[]
}
```

After modifying the file `schema.prisma`, we should run this command to update the migration files and create another one:

```bash
npx prisma migrate dev
```

Now we will try to seed some companies in the database. To do that, we will create a file called `seed.ts` in Prisma directory:

```tsx
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

const companies = [
  {
    name: "Adservio",
    description: "Great Place to Work",
    website: "www.adservio.fr",
  },
  {
    name: "Adservio Academy",
    description: "Great Place to Learn",
    website: "www.adservio-academy.fr",
  },
  {
    name: "Iriguard",
    description: "Great Place to be Secure",
    website: "www.iriguard.fr",
  }
];

async function main() {

  for (const company of companies) {
    const { name, description, website } = company;
    const categoryData = await prisma.company.upsert({
      where: { website },
      update: {},
      create: {
        name,
        description,
        website
      },
    });
    
  }
}
main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

After that, we should add this line to the `package.json`:

```bash
"prisma": {
    "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
  },
```

And finally, we should execute this command:

```bash
npx prisma migrate reset
```

If you get this error:

```bash
An error occurred while running the seed command:
Error: Command failed with ENOENT: ts-node --compiler-options {"module":"CommonJS"} prisma/seed.ts
spawn ts-node ENOENT
```

You should install ts-node:

```bash
npm install ts-node
```

After re-executing the command, to show the results, we can execute Prisma Studio with the command:

```bash
npx prisma studio
```

Here are the results:

![Result Table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/np95k96yvzp3cbvg0ajj.png)
Now we will create a route that will help us to create users. Here is the code of the index.ts of this route:

```tsx
import { component$ } from '@builder.io/qwik';
import { routeAction$,routeLoader$, zod$, z, Form } from '@builder.io/qwik-city';
import { PrismaClient } from '@prisma/client';

export const useGetCompanies = routeLoader$(async () => {
  const prisma = new PrismaClient();
  const companies = await prisma.company.findMany();
  return companies;
});

export const useCreateEmployee = routeAction$(
  async (data) => {
    const prisma = new PrismaClient();
    console.log(data);
    const employee = await prisma.employee.create({
      data
    });
    return employee;
  },
  zod$({
    name: z.string(),
    email: z.string().email(),
    companyId: z.string().regex(/^\d+$/).transform(Number)
  })
);

export default component$(() => {
  const createEmployeeAction = useCreateEmployee();
  const companies = useGetCompanies();
  return (
    <section>
      <h1>Create User</h1>
      <Form action={createEmployeeAction}>
        <label>
          Name
          <input type="text" name="name" />
        </label>
        <label>
          Email
          <input type="email" name="email" />
        </label>
        <label>
          Companies
          <select  name="companyId" data-choose-theme>
            <option  value="0">Default</option>
            {companies.value.map((company) => (
                <option class="text-primary" value={company.id} key={company.id}>{company.name}</option>
            ))}
          </select>
        </label>

        <button type="submit">Create</button>
      </Form>
      {createEmployeeAction.value && (
        <div>
          <h2>Employee created successfully!</h2>
        </div>
      )}
    </section>
  );
});
```

In the creation, we should choose a name, an email, and the company. To get the list of companies, we used `routeLoader$` with a `findMany()` that will return the list of companies. R`outeLoader$` is good for having data rendered in the server and sent it to the client as a serialized HTML.

After that, we use `routeAction$` to create a user after submitting the form. It allows us to perform submitting and return from the server a result to the client in order to update our UI.

Here are the results:

![Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/io63m27yuw5vllj84emo.png)

And if we click on company:

![Result final](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/udmmiyvtegrtjzluzs1a.png)

As we can see, Prisma Studio helps us to visualize all the relations between our tables.

Qwik and Prisma can be integrated easily, and with Qwik, we benefit from using  `routeLoader$` and `routeAction$`, which help us to have a great performance with an exceptional DX because, with these features, we don't have to keep track of which code we will execute in the server or in the client, the framework does that for us.