Next

Next_thumb.jpg

Product Model

Prisma Client

  • 개발 환경에서 Next는 리로드 시, prisma 클라이언트를 새로 생성하여 연결한다
  • 이를 방지하기 위해, 글로벌 변수를 선언한 후 할당된 prisma가 없을 경우에만 생성하도록 한다.
import { PrismaClient } from "@prisma/client";

declare global {
  var client: PrismaClient | undefined;
}

const client = global.client || new PrismaClient();

if (process.env.NODE_ENV === "development") global.client = client;

Product Detail

select

레코드에서 필요한 칼럼만 선택하기

const product = await client.product.findUnique({
  where: { id: +id.toString() },
  include: {
    user: {
      // 유저 레코드에서 id, name, avatar만 뽑기
      select: {
        id: true,
        name: true,
        avatar: true,
      },
    },
  },
});

Related Products

연관 검색

단어를 띄어쓰기로 스플릿한 후, 각 단어와 일치하는 다른 레코드 탐색

// 상품명을 띄어쓰기로 스플릿해서 해당 단어와 일치하는 다른 상품을 연관 상품으로 검색
const terms = product?.name
  .split(" ")
  .map((word) => ({ name: { contains: word } }));

const relatedProducts = await client.product.findMany({
  where: {
    OR: terms,
    // 검색 단어를 추출한 상품은 연관 상품에서 제외
    AND: {
      id: {
        not: product?.id,
      },
    },
  },
  include: {
    user: {
      select: {
        id: true,
      },
    },
  },
});

Favorite Products

Toggle Favorite

로그인 유저가 해당 product에 좋아요를 눌렀는지 확인한 후, 눌렀으면 삭제 혹은 안눌렀다면 생성

const alreadyExists = await client.fav.findFirst({
      where: {
        productId: +id.toString(),
        userId: session.user.id,
      },
    });

    if (alreadyExists) {
      // 삭제
      await client.fav.delete({
        where: {
          id: alreadyExists.id,
        },
      });
    } else {
      // 생성
      await client.fav.create({
        data: {
          user: {
            connect: {
              id: session.user.id,
            },
          },
          product: {
            connect: {
              id: +id.toString(),
            },
          },
        },
      });

delete

기존 DB 레코드를 삭제 (id 또는 유니크한 속성으로만 삭제 가능)

deleteMany

여러 레코드를 삭제 (유니크하지 않은 속성으로도 삭제 가능)

Bound & Unbound Mutation

Mutate

캐시된 데이터를 변형하기 위한 함수

input

  • data? : 캐시된 데이터
  • shouldRevalidate? : 서버에서 받은 데이터로 갱신 여부

Bound Mutation

  • 동일한 컴포넌트 안에서 데이터를 변형
  • useSWR Hook 사용
const { data, mutate } = useSWR("api url");
mutate({ ...data, isLiked: !data.isLiked }, false);

Unbound Mutation

  • 다른 컴포넌트에서 데이터를 변형
  • useSWRConfig Hook 사용
const { mutate } = useSWRConfig();
mutate("/api/users/me", (prev) => ({ ...prev, ok: false }), false);

Counting Relationships

참조되고 있는 레코드 기준에서 참조하고 있는 레코드의 개수를 추가

// product를 가리키고 있는 fav의 개수(_count)를 추가
const products = await client.product.findMany({
  include: {
    _count: {
      select: {
        fav: true,
      },
    },
  },
});

Models

Referencing

다른 모델의 키 참조하기

User

  • 동네 생활 탭에서 유저는 post, answer, wonderings 모델에서 모두 참조되고 있음
model User {
  id         Int         @id @default(autoincrement())
  phone      String?     @unique
  email      String?     @unique
  name       String
  avatar     String?
  createdAt  DateTime    @default(now())
  updatedAt  DateTime    @updatedAt
  tokens     Token[]
  products   Product[]
  fav        Fav[]
  posts      Post[] // 여러 post를 가지고 있음
  answers    Answer[] // 여러 answer를 가지고 있음
  wonderings Wondering[] // 여러 wonrdering을 가지고 있음
}

Renferences

model Post {
  id        Int         @id @default(autoincrement())
  userId    Int
  user      User        @relation(fields: [userId], references: [id], onDelete: Cascade) // user에게 속함
  question  String      @db.MediumText
  createdAt DateTime    @default(now())
  updatedAt DateTime    @updatedAt
  answers   Answer[]
  Wondering Wondering[]

  @@index([userId]) // 현재 테이블에서 참조키와 같은 필드를 명시
}

model Answer {
  id        Int      @id @default(autoincrement())
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade) // user에게 속하면서
  userId    Int
  answer    String   @db.MediumText
  post      Post     @relation(fields: [postId], references: [id], onDelete: Cascade) // 동시에 post에도 속한다
  postId    Int
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([userId])
  @@index([postId])
}

model Wondering {
  id        Int      @id @default(autoincrement())
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade) // user에게 속하면서
  userId    Int
  post      Post     @relation(fields: [postId], references: [id], onDelete: Cascade) // 동시에 post에도 속한다
  postId    Int
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([userId])
  @@index([postId])
}

Leave a comment