Hun's Blog

Introducing Major improvements to Prisma v2.6.0 본문

Backend/GraphQL

Introducing Major improvements to Prisma v2.6.0

jhk-im 2020. 11. 25. 17:35

github.com/prisma/prisma/releases

 

Releases · prisma/prisma

Modern database access (ORM alternative) for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB & SQLite - prisma/prisma

github.com

 

1. Prisma 스키마 파일의 수동 변경 사항을 유지하여 보다 강력한 introspection 지원

prisma의 migrate가 불안정하기 때문에 일반 sql이나 migration 도구를 활용하여 migrate하는 경우가 많습니다. hackatalk-server에서 예를 들어보자면 database tool 로 dbeaver를 사용하고 있습니다. deaver에서 직접 table을 생성하고 column을 작성할 수있습니다. 그렇게 생성된 테이블은 자체적으로 migrate되어 스키마로 저장됩니다. 그렇게 저장된 스키마를 prisma로 introspect하여 가져오게됩니다. 예제를 통해 알아보도록 하겠습니다.

// dbvear에서 migrate한 스키마 예시
CREATE TABLE "public"."users" (
   id SERIAL PRIMARY KEY NOT NULL,
   name VARCHAR(255),
   email VARCHAR(255) UNIQUE NOT NULL
 );
CREATE TABLE "public"."posts" (
   id SERIAL PRIMARY KEY NOT NULL,
   title VARCHAR(255) NOT NULL,
   "createdAt" TIMESTAMP NOT NULL DEFAULT now(),
   content TEXT,
   published BOOLEAN NOT NULL DEFAULT false,
   "authorId" INTEGER NOT NULL,
   FOREIGN KEY ("authorId") REFERENCES "public"."users"(id) 
);  
CREATE TABLE "public"."profiles" (
   id SERIAL PRIMARY KEY NOT NULL,
   bio TEXT,
   "userId" INTEGER UNIQUE NOT NULL,
   FOREIGN KEY ("userId") REFERENCES "public"."users"(id) 
);

prisma의 schema.prisma에는 다음과같이 스키마가 비어있는 상태입니다.

schema.prisma

$ npx prisma introspect

prisma에서 제공하는 introspect 명령어를 사용하면 아래와 같이 스키마를 자동으로 작성하게 됩니다. (해당 기능은 2.6.0 이전에도 제공되었습니다.)

introspect

이렇게 작성된 스키마를 다음과 같은 이유로 변경하고자 합니다.

  1. 모델명이 prisma의 PascalCasing형식을 준수하지 않음 ex) posts (x) → Post
  2. posts 모델 내부의 users와 users라는 모델명이 중복됨
  3. posts 내부의 users를 조금 더 어울리는 autor로 변경하고 싶음
  4. profiles 모델의 users도 유사한 문제 발생

변경된 schema.prisma

$ npx prisma generate

위 명령어를 입력하 변경된 내용으로 스키마를 활용할 수 있습니다. 하지만 데이터베이스에서 새로운 내용이 추가되었다고 가정해보겠습니다. 여기서 re-introspection 해야합니다. 그렇게 되면 수정 했던 모든것들이 아래와 같이 원래 상태로 되돌아 갑니다.

 

이번 release의 목적은 introspection 했을 때 수정된 사항들을 유지하는 것입니다. 사실 이전에도 가능했지만 비공식적이며 불안정했습니다. prisma에서 공식적으로 제공하는 방법을 소개하도록 하겠습니다.

아래와 같이 스키마를 변경합니다.

model Post {
id Int @default(autoincrement()) @id
title String
createdAt DateTime @default(now())
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id])@@map("posts")
}model Profile {
id Int @default(autoincrement()) @id
bio String?
userId Int @unique
user User @relation(fields: [userId], references: [id])@@map("profiles")
}model User {
id Int @default(autoincrement()) @id
name String?
email String @unique
posts Post[]
profile Profile?@@map("users")
}

이렇게 작성하고 introspect하면 아래와 같이 수정내용이 유지됩니다.

 

 

prisma v2.6.0 re-introspect

introspect 사용법

출처 https://www.prisma.io/docs/getting-started/setup-prisma/add-to-existing-project-typescript-postgres$ prisma 

 

$ prisma introspect   
-> 기존 schema.prisma 파일을 introspection  
$ prisma introspect --schema=./shcema.prisma   
-> 지정된 schema.prisma 파일을 introspection   
$ prisma introspect --print  
-> 시스템에 저장하지 않고 콘솔에 프린트하여 확인  
flag  --force  
-> 현재 schema.prisma 무시

 

@map / @@map 사용법

설명을 위해 dbeaver에 다음의 스키마를 생성하겠습니다.

CREATE TABLE "public"."my_user" (
user_id SERIAL PRIMARY KEY NOT NULL,
first_name TEXT,
last_name TEXT UNIQUE NOT NULL
);

introspection하면 아래와 같이 생성되겠죠?

model my_user {
user_id Int @default(autoincrement()) @id
first_name String?
last_name String @unique 
}

 

위 스키마를 수정하면 re-introspection 했을 때 원상복구 됩니다. 데이터베이스는 유지하면서 prisma 스키마에서만 모델명과 컬럼명을 변경하고자 할 때 다음과 같이 사용합니다.

모델명 = ‘@@map’ / 컬럼명 = ‘@map’

model MyUser {
userId Int @default(autoincrement()) @id @map("user_id")
firstName String? @map("first_name")
lastName String @map("last_name") @unique@@map("my_user")
}

 

이제 introspection을 하면 수정한 내용이 변경되지 않습니다.

출력 메세지

해당 내용은 아래의 prisma issues에서 시작되었으며 자세히 알아볼 수 있습니다.

 

 

Customize Introspection · Issue #2425 · prisma/prisma

Context Since Prisma Migrate is currently experimental, users need to migrate their DB with plain SQL or another migration tool. They can then introspect the DB schema to obtain their Prisma schema...

github.com

2. update query에 atomic number operations 추가

이번 release에서 update query 에 대한 atomic number 연산이 소개되었습니다. 이를 활용해 특정 필드의 값을 atomic으로 업데이트 할 수 있습니다.

사용법

Int  Float fields에 5가지 atomic operations 도입 :

  • increment: x → 값을 x만큼 더하기
  • decrement: x → 값을 x만큼 빼기
  • multiply: x → 값을 x로 곱하기
  • divide: x → 값을 x로 나누기
  • set: x → 값을 x로 셋팅

Note: 각 field에 한번의 작업만 할 수 있음

test를 위해 다음의 스키마를 데이터베이스에 생성하고 정보를 입력하였습니다.

CREATE TABLE "public"."TestUser" (
id SERIAL PRIMARY KEY NOT NULL,
email TEXT UNIQUE NOT NULL,
point FLOAT,
age INTEGER,
credits INTEGER,
karma INTEGER,
count INTEGER
); 

INSERT INTO "public"."TestUser" 
(email, point, age, credits, karma, count) 
VALUES ('john@prisma.io', 1.5, 31, 3000, 20, 30);

schema.prisma에 다음 내용을 추가합니다.

// previewFeatures = [“atomicNumberOperations”]

atomicNumberOperations

 

prisma v2.6.0 이전에는 각 필드에 연산하는 값을 update할 때 두가지 방법을 사용했습니다. 첫번째는 findmany로 해당 필드를 찾아서 다시 update 변경해주는 방법인데 query를 2번 사용한다는 점에서 대부분 아래와 같이 사용했습니다.

update query

 

직접 업데이트 쿼리를 작성해서 보내는 것이죠. 해당 쿼리를 실행해보도록 하겠습니다.

$ npx ts-node src/index.ts

before

 

after

 

dbeaver에서 update가 적용된 것을 확인할 수 있습니다. 이제 이번 release에서 추가된 atomic operations를 사용해서 연산한 내용을 update해보도록 하겠습니다.

아래와 같이 사용합니다.

// v2.6.0 atomic operations
const post = await prisma.testUser.update({
    where: {
      email: 'john@prisma.io',
    },
    data: {
      point: {
        set: 123.5 // this just sets the value
      },
      age: {
        increment: 1, // age + 1
      },
      credits: {
       decrement: 250, // credits - 250
      },
      karma: {
        multiply: 3, // karma * 3
      },
      count: {
        divide: 5, // chocolates / 5
      },
    },
  })
}

update result

이 방법은 편리하게 사용할 수 있다는 점과 더불어 race condition을 방지할 수 있다고 prisma 공식 문서에서 설명하고 있습니다.

CRUD (Reference)

 

CRUD (Reference)

This page provides a detailed reference of the auto-generated CRUD queries that are exposed in the Prisma Client API, such as findOne, findMany, create, ...

www.prisma.io

update

업데이트 쿼리는 기존 데이터베이스 레코드를 업데이트합니다. select 및 include 옵션을 사용하여 반환 된 object에 포함되어야하는 속성을 결정할 수 있습니다.

산술 연산 (더하기, 빼기, 곱하기, 나누기)을 수행하려면 atomic update를 사용하여 race condition을 방지하십시오.

 

 

경쟁 상태 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 논리 상태에서의 경쟁 상태 공학 분야에서 경쟁 상태(race condition)란 둘 이상의 입력 또는 조작의 타이밍이나 순서 등이 결과값에 영향을 줄 수 있는 상태를 말

ko.wikipedia.org