본문 바로가기
2. 우당탕탕 개발자/2-2. 상세 노트

Prisma2 의 onDelete, Cascade 대신 쓸 수 있는 방법

by Little Monkey 2020. 11. 4.
반응형

요즘은 노마드코더의 인스타그램 강의를 보며 클론 코딩을 하고 있다. 중점적으로 보려고 하는 것은 단순히 해당 기능을 어떻게 코드로 구현했냐 / 안했냐, 따라 치냐/ 안치냐는 아니다. 지난 번 코드스테이츠 마지막 프로젝트 때 graphql 과 typeORM을 도입했는데, 한정된 시간 안에 원하는 기능을 구현하다보니 graphql 의 의도에 맞게 쓴 것인지 의문이 들었다. 다음의 목차는 노마드코더 인스타그램 클론 코딩에서 내가 얻고자 하는 것이다. 

 

- graphql 을 전문가는 어떻게 사용하는지

- prisma는 기존에 사용해왔던 sequelize와 typeORM 과 같은 ORM 과 어떤 차이가 있는지

- react에 대한 복습

- 프로젝트에선 백엔드만 했는데, 프론트 엔드인 react-native 새로 배우기


노마드코더의 인스타클로닝은 prisma 1을 가지고 진행하기 때문에, prisma2의 공식 문서를 보면서 다른 점은 적당히 스킵하면서 듣고 있다. prisma2는 ORM은 아니라고 주장하지만, sequelize나 typeORM을 쓰는 것처럼 prisma1의 불편한 점이 많이 개선되었다. 그러나 CASCADE가 지원되지 않아 관계가 복잡한 테이블을 지울 때, 에로사항이 있었다. 

 

 

예를 들면, Post 라는 모델이 User와 n: 1 관계를 가진다면, User 를 지울 경우, 해당 유저가 작성한 Post 도 함께 삭제되어야 한다.

model User {
  id Int
  username String
  posts Post[]
}

model Post {
  id Int
  author User? @relation(fields : [userId], references:[id])
  authorId Int?
 }

 

그러나 CASCADE를 지원하지 않는 prisma2에선 user를 지울 경우, 에러가 발생한다. 프리즈마의 원칙에 위배된다면서. 그렇다면, cascade를 사용할 수 없다면, 우리는 어떻게 해야 할까?

 

방법 1. 노가다 : post를 먼저 지운 후, 해당 user를 지운다. 

해당 방법은 가장 확실하다. 직관적으로 떠올릴 수 있다. user를 지우기 위해 관련된 모든 필드를 미리 지운다. 하지만, 관계가 복잡할 경우 이 방법은 당연히 좋지 않다. 앞선 예시와 같이 간단한 관계의 데이터 모델에서만 사용이 가능하다. 

 

방법2. 사용하고 있는 db에 직접 cascade를 설정한다.

mysql을 사용하고 있다면, 쿼리문을 이용해서 FK나 cascade를 설정해주는 것이다. 그러나 이 방법을 쓸 경우 prisma가 에러를 내지 않는지는 모르겠다. 

 

방법 3. Set Null을 이용해 관계를 끊어라.

post의 author를 null로 설정하는 것이다. 프리즈마는 해당 방법을 권하는 듯 보인다. 

 

방법4. 해당 패키지를 사용한다. (paljs.com/plugins/delete/ )

프리즈마2 공식 문서에서도 제공되어 있다. 2버전은 ondelte와 같은 cascade를 지원하지 않는다. 정 쓰고 싶으면 같이 개발한 이 사람의 패키지를 사용하렴^^ 

 

그래서 방법 4을 사용했다. 관계가 없는 데이터를 남기고 싶지 않아서....

 

cascade(delete)하고 싶은 필드 상단 위에 다음과 같이 주석을 달아 놓는다. /// <- 슬러시 3번이다!

/// @onDelete(CASCADE)

model User {
  id Int
  username String
  /// @onDelete(CASCADE)
  posts Post[]
}

model Post {
  id Int
  author User? @relation(fields : [userId], references:[id])
  authorId Int?
 }

 

그리고 자주 사용할 것 같으면, graphql server의 context에 다음과 같이 추가한다.

class Prisma extends PrismaClient {
  constructor(options) {
    super(options);
  }

  async onDelete(args) {
    const prismaDelete = new PrismaDelete(this);
    await prismaDelete.onDelete(args);
  }
}

const prisma = new Prisma();

const server = new GraphQLServer({
  schema,
  context: ({ request }) => {
    return { request, prisma };
  },
});

 

그런 다음 사용하고자 하는 graphql resolver에 다음과 같이 작성한다.

export default {
  Mutation: {
    resolver: async (_, __, { prisma, request }) => {
     // 중략
          await prisma.onDelete({
            model: 'User',
            where: { id : 1 },
            deleteParent: true,
          });
     // 중략
    },
  },
};

 

반응형

댓글