The Future Is Here: Qwik Meets Prisma Innovatively

ayoub_alouane

Ayoub Alouane

Posted on August 17, 2023

The Future Is Here: Qwik Meets Prisma Innovatively

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:

Integrate Prisma to Qwik

Prerequisites

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

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:

npm create qwik@latest
Enter fullscreen mode Exit fullscreen mode

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

npm start
Enter fullscreen mode Exit fullscreen mode

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

npm run qwik add prisma
Enter fullscreen mode Exit fullscreen mode

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

Prisma Folder

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:

// 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[]
}
Enter fullscreen mode Exit fullscreen mode

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

npx prisma migrate dev
Enter fullscreen mode Exit fullscreen mode

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:

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);
  });
Enter fullscreen mode Exit fullscreen mode

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

"prisma": {
    "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
  },
Enter fullscreen mode Exit fullscreen mode

And finally, we should execute this command:

npx prisma migrate reset
Enter fullscreen mode Exit fullscreen mode

If you get this error:

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
Enter fullscreen mode Exit fullscreen mode

You should install ts-node:

npm install ts-node
Enter fullscreen mode Exit fullscreen mode

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

npx prisma studio
Enter fullscreen mode Exit fullscreen mode

Here are the results:

Result Table
Now we will create a route that will help us to create users. Here is the code of the index.ts of this route:

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>
  );
});
Enter fullscreen mode Exit fullscreen mode

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. RouteLoader$ 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

And if we click on company:

Result final

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.

💖 💪 🙅 🚩
ayoub_alouane
Ayoub Alouane

Posted on August 17, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related