Prisma ORM: 기본 개념과 동작 원리

2024. 7. 23. 18:16ORM

Prisma ORM: 기본 개념과 동작 원리

 

Prisma ORM이란?

Prisma ORM은 차세대 오픈소스 ORM입니다.

ORM은 "Object-Relational Mapping"의 약자로, 객체-관계 매핑을 의미합니다. ORM은 데이터베이스의 테이블과 프로그래밍 언어의 객체 사이의 매핑을 자동화하여, 데이터베이스와의 상호작용을 더 쉽고 효율적으로 만들어줍니다. 왜냐하면 개발자가 객체 지향 언어로 데이터베이스의 데이터를 더 쉽게 조작할 수 있게 해 주기 때문입니다. ORM을 사용하면 SQL 쿼리 없이 데이터를 데이터베이스에 저장하고 관리할 수 있습니다.

다음과 같은 구성 요소로 이루어져 있습니다.

Prisma Client: 자동 생성되고 타입 안전한 Node.js 및 TypeScript용 쿼리 빌더
Prisma Migrate: 마이그레이션 시스템
Prisma Studio: 데이터베이스의 데이터를 보고 편집할 수 있는 GUI로 이 부분은 오픈소스가 아닙니다.

Prisma Client는 모든 Node.js(지원되는 버전) 또는 TypeScript 백엔드 애플리케이션(서버리스 애플리케이션 및 마이크로서비스 포함)에서 사용할 수 있습니다. 여기에는 REST API, GraphQL API, gRPC API 또는 데이터베이스가 필요한 모든 것이 포함될 수 있습니다.

Prisma 스키마는 강력한 데이터 모델링 기능을 가지고 있습니다. 예를 들어, "Prisma-lelvel"의 관계 필드를 정의할 수 있어 Prisma 클라이언트 API에서 relations 작업을 더 쉽게 할 수 있습니다. 자세히 알아보겠습니다.

relations

관계는 프리즈마 스키마에서 두 모델 간의 연결입니다. 예를 들어, 한 사용자가 많은 블로그 글을 가질 수 있으므로 사용자와 게시물 사이에는 일대다 관계가 있습니다. 다음 프리즈마 스키마는 사용자 모델과 게시물 모델 간의 일대다 관계를 정의합니다.

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int // relation scalar field  (used in the `@relation` attribute above)
}
두 개의 관계 필드: User의 posts와 Post의 author. 관계 필드는 Prisma ORM level에서 모델 간의 연결을 정의하며 데이터베이스에는 존재하지 않습니다. 이러한 필드는 Prisma Client를 생성하는 데 사용됩니다.

Post의 authorId는 @relation 속성에서 참조하는 스칼라 필드입니다. 이 필드는 데이터베이스에 존재하며 게시물과 사용자를 연결하는 외래 키입니다.
다음 엔티티 관계 다이어그램은 관계형 데이터베이스의 User 테이블과 Post 테이블 간에 동일한 일대다 관계를 정의합니다. 관계 필드는 존재하지 않는 것을 확인할 수 있습니다.

 

Prisma ORM은 어떻게 동작하는가?

Prisma ORM 툴킷을 사용하는 모든 프로젝트는 Prisma schema로 시작합니다. Prisma schema는 개발자가 직관적인 데이터 모델링 언어로 애플리케이션 모델을 정의할 수 있게 해 줍니다. 또한 데이터베이스 연결을 포함하고, generator를 정의합니다.

//schema.prisma

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

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

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields: [authorId], references: [id])
  authorId  Int?
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}
  • Prisma schema는 datasoruce, generator, model 이 세 가지 요소로 구성됩니다.
  • 데이터 모델은 데이터베이스에서 데이터를 어떻게 저장할지를 정의하는 구조입니다.
  • Prisma schema에서는 모델이라는 개념을 사용해서 데이터베이스의 테이블(관계형 데이터베이스)이나 컬렉션(MongoDB)을 정의합니다.
  • Prisma Client를 사용하면, model을 통해 생성된 테이블에서 데이터를 추가하거나 조회할 수 있습니다.

 

Prisma Client 사용하기

Prisma Client를 사용하려면 첫 번째 단계로 @prisma/client npm 패키지를 설치해야 합니다:

npm install @prisma/client
 

@prisma/client 패키지를 설치하면, prisma generate 명령이 자동으로 실행되어 Prisma 스키마를 읽고 Prisma Client 코드를 생성합니다. 기본적으로 생성된 코드는 node_modules/.prisma/client 폴더에 저장됩니다.

데이터 모델을 변경한 후에는, node_modules/.prisma/client 폴더의 코드가 업데이트되도록 Prisma Client를 수동으로 다시 생성해야 합니다:

npx prisma generate

 

Prisma Client 사용 예시

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

//Retrieve all User records from the database
// Run inside `async` function
const allUsers = await prisma.user.findMany()

//Include the posts relation on each returned User object
// Run inside `async` function
const allUsers = await prisma.user.findMany({
  include: { posts: true },
})

// Filter all Post records that contain "prisma"
// Run inside `async` function
const filteredPosts = await prisma.post.findMany({
  where: {
    OR: [
      { title: { contains: 'prisma' } },
      { content: { contains: 'prisma' } },
    ],
  },
})

// Create a new User and a new Post record in the same query
// Run inside `async` function
const user = await prisma.user.create({
  data: {
    name: 'Alice',
    email: 'alice@prisma.io',
    posts: {
      create: { title: 'Join us for Prisma Day 2020' },
    },
  },
})

// Update an existing Post record
// Run inside `async` function
const post = await prisma.post.update({
  where: { id: 42 },
  data: { published: true },
})

 

Prisma ORM Workflow

Data model을 Prisma schema로 가져오는 방법에는 두 가지가 있습니다. 어떤 접근 방식을 선택하느냐에 따라 기본 Prisma ORM 워크플로가 달라질 수 있습니다.

방법 01. Prisma Migrate 사용

Prisma ORM의 통합 데이터베이스 마이그레이션 도구인 Prisma Migrate를 사용할 때의 작업 흐름은 다음과 같습니다:

  1. 'schema.prisma' 파일을 수정해 데이터 모델을 업데이트 합니다.
  2. prisma migrate dev로 개발 환경의 데이터베이스에 변경사항을 적용합니다.
  3. 애플리케이션 코드에서 Prisma Client를 사용하여 데이터베이스에 접근합니다.

prisma migrate dev 명령어 사용 시 다음과 같은 에러가 발생할 수 있습니다. 
1. prisma migrate 이전에 데이터베이스를 사용 중이었을 경우
2. 데이터베이스의 데이터가 유지되어야 하는 경우
에러메시지에서도 알 수 있다시피, 위 경우에는 Baselining을 통해 데이터베이스 마이그레이션 기록을 초기화해줘야 합니다. 데이터베이스에 이미 존재하는 테이블과 필드가 있는 상황에서 Prisma Migrate가 이를 다시 생성하려 하면 오류가 발생할 수 있습니다. 베이스라이닝은 이러한 문제를 해결하는 방법입니다. 베이스라이닝을 통해 Prisma Migrate에게 특정 마이그레이션들이 이미 적용된 것으로 간주하도록 설정할 수 있습니다. 이를 통해 Prisma Migrate는 해당 마이그레이션들을 건너뛰고, 실제로 필요한 새로운 마이그레이션만을 적용하게 됩니다.

참고: migrate-baseline

 

방법 02.  SQL 마이그레이션과 introspection

  1. SQL 등을 활용해서 데이터베이스 스키마를 변경합니다.
  2. 데이터베이스 introspection: 현재 데이터베이스 스키마를 기반으로 Prisma 스키마를 업데이트합니다.
  3. Prisma Client API를 (재)구성하기(선택): 데이터베이스 스키마를 변경한 후, 필요에 따라 Prisma Client API의 설정을 조정할 수 있습니다.
  4. (재)생성된 Prisma Client 사용하기: Prisma Client를 재생성하여 최신 스키마를 반영하도록 하고, 애플리케이션 코드에서 Prisma Client를 사용하여 데이터베이스에 접근합니다.

이상으로 Prisma의 기본 개념과 동작 원리, 사용법에 대해 알아보았습니다.

 

참고

What is Prisma ORM? | Prisma Documentation

Relations | Prisma Documentation

ORM 이해하기 | F-Lab