[캐럿마켓 클론] Products
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