Subset์ Entity์ ํน์ ํ๋ ์กฐํฉ์ ๋ฏธ๋ฆฌ ์ ์ํ์ฌ API ์๋ต์ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๊ธฐ๋ฅ์
๋๋ค. Sonamu UI์ Subset ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด ์๊ฐ์ ์ผ๋ก Subset์ ์ ์ํ๊ณ ํธ์งํ ์ ์์ต๋๋ค.
Subset์ด๋?
Subset์ Entity์ ์ผ๋ถ ํ๋๋ง ์ ํ์ ์ผ๋ก ๊ฐ์ ธ์ค๋ ์ฌ์ ์ ์๋ ํ๋ ๊ทธ๋ฃน์
๋๋ค.
์ฌ์ฉ ์ด์
| ๋ฌธ์ | Subset ํด๊ฒฐ์ฑ
|
|---|
| ๋ถํ์ํ ๋ฐ์ดํฐ ์ ์ก | ํ์ํ ํ๋๋ง ์ ํ |
| ์ผ๊ด์ฑ ์๋ ์๋ต | ํ์คํ๋ ํ๋ ์กฐํฉ |
| ๋ณต์กํ JOIN | ๊ด๊ณ ๋ฐ์ดํฐ ํฌํจ ์ฌ๋ถ ์ ์ด |
| ์ฑ๋ฅ ์ ํ | ์ต์ ๋ฐ์ดํฐ๋ง ์กฐํ |
// โ ๋ชจ๋ ํ๋ ์กฐํ (๋นํจ์จ์ )
const users = await UserModel.findMany();
// โ
Subset์ผ๋ก ํ์ํ ํ๋๋ง ์กฐํ
const users = await UserModel.findMany({ subset: "A" });
// โ id, email, name๋ง ๋ฐํ
Subset ๊ด๋ฆฌ ํ๋ฉด
Subset ๊ด๋ฆฌ ํ๋ฉด์ ๋ ๊ฐ์ง ์ฃผ์ ์์ญ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค:
- ์ผ์ชฝ Sidebar: Entity ๋ชฉ๋ก๊ณผ ๊ฐ Entity์ Subset ๋ชฉ๋ก
- ์ค๋ฅธ์ชฝ Content: ์ ํํ Subset์ ํ๋ ์ ํ ์ฒดํฌ๋ฐ์ค
Subset ์์ฑ
1. Entity ์ ํ
์ผ์ชฝ ๋ชฉ๋ก์์ Subset์ ์ถ๊ฐํ Entity๋ฅผ ์ ํํฉ๋๋ค.
2. Subset ์ถ๊ฐ
[Add Subset] ๋ฒํผ์ ํด๋ฆญํ์ฌ ์ Subset์ ์์ฑํฉ๋๋ค.
| ํ๋ | ์ค๋ช
| ์์ |
|---|
| Subset ID | Subset ์๋ณ์ (A-Z) | A, B, C |
| Description | Subset ์ค๋ช
| ๊ธฐ๋ณธ ๋ชฉ๋ก์ฉ, ์์ธ ์กฐํ์ฉ |
Subset ID๋ ์ผ๋ฐ์ ์ผ๋ก ์ํ๋ฒณ ํ ๊ธ์(A, B, Cโฆ)๋ฅผ ์ฌ์ฉํฉ๋๋ค.
3. ํ๋ ์ ํ
์์ฑ๋ Subset์์ ํฌํจํ ํ๋๋ฅผ ์ ํํฉ๋๋ค:
๊ธฐ๋ณธ ํ๋:
โ id โ ํ์ (ํญ์ ํฌํจ)
โ email
โ name
โก password โ ๋ฏผ๊ฐ ์ ๋ณด ์ ์ธ
โก bio
โ created_at
๊ด๊ณ ํ๋:
โ posts โ Post.Subset A
โ profile โ Profile.Subset B
Subset ์ข
๋ฅ
Subset A (๊ธฐ๋ณธ ๋ชฉ๋ก)
์ฉ๋: ๋ชฉ๋ก ์กฐํ ์ ์ฌ์ฉ
ํฌํจ: ํ์ ์ ๋ณด + ์์ฝ ์ ๋ณด
// User.Subset A
{
id: true,
email: true,
name: true,
created_at: true,
}
์ฌ์ฉ ์์:
// ์ฌ์ฉ์ ๋ชฉ๋ก
const users = await UserModel.findMany({ subset: "A" });
Subset B (์์ธ ์กฐํ)
์ฉ๋: ๋จ์ผ ๋ ์ฝ๋ ์์ธ ์กฐํ
ํฌํจ: ๋ชจ๋ ์ผ๋ฐ ์ ๋ณด (๋ฏผ๊ฐ ์ ๋ณด ์ ์ธ)
// User.Subset B
{
id: true,
email: true,
name: true,
bio: true,
profile_image: true,
created_at: true,
updated_at: true,
}
์ฌ์ฉ ์์:
// ์ฌ์ฉ์ ์์ธ
const user = await UserModel.findById(1, { subset: "B" });
Subset C (๊ด๊ณ ํฌํจ)
์ฉ๋: ๊ด๊ณ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ ์กฐํ
ํฌํจ: ๊ธฐ๋ณธ ์ ๋ณด + ๊ด๊ณ Entity
// Post.Subset C
{
id: true,
title: true,
content: true,
author: "User.B", // User์ Subset B ํฌํจ
comments: "Comment.A", // Comment์ Subset A ํฌํจ
created_at: true,
}
์ฌ์ฉ ์์:
// ๊ฒ์๊ธ + ์์ฑ์ + ๋๊ธ
const post = await PostModel.findById(1, { subset: "C" });
๊ด๊ณ ํ๋ ์ค์
belongsTo ๊ด๊ณ
์์: Post โ User (์์ฑ์)
โ author โ User.Subset B
์ ํํ๋ฉด Post๋ฅผ ์กฐํํ ๋ ์์ฑ์(User) ์ ๋ณด๋ ํจ๊ป ๊ฐ์ ธ์ต๋๋ค:
// ๊ฒฐ๊ณผ
{
id: 1,
title: "Hello World",
author: {
id: 10,
email: "[email protected]",
name: "John Doe",
// User.Subset B์ ๋๋จธ์ง ํ๋...
}
}
hasMany ๊ด๊ณ
์์: User โ Post[] (์์ฑํ ๊ธ ๋ชฉ๋ก)
โ posts โ Post.Subset A
์ ํํ๋ฉด User๋ฅผ ์กฐํํ ๋ ์์ฑํ Post ๋ชฉ๋ก๋ ํจ๊ป ๊ฐ์ ธ์ต๋๋ค:
// ๊ฒฐ๊ณผ
{
id: 10,
email: "[email protected]",
name: "John Doe",
posts: [
{ id: 1, title: "First Post", ... },
{ id: 2, title: "Second Post", ... },
]
}
N+1 ๋ฌธ์ ์ฃผ์: hasMany ๊ด๊ณ๋ฅผ Subset์ ํฌํจํ๋ฉด ์ถ๊ฐ ์ฟผ๋ฆฌ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
ํ์ํ ๊ฒฝ์ฐ์๋ง ํฌํจํ์ธ์.
Subset ์์
ํ๋ ์ถ๊ฐ/์ ๊ฑฐ
- Subset ์ ํ
- ํ๋ ์ฒดํฌ๋ฐ์ค ํด๋ฆญ
- [Save] ๋ฒํผ ํด๋ฆญ
๋ณ๊ฒฝ์ฌํญ ์ฆ์ ๋ฐ์:
Before: { id, email, name }
After: { id, email, name, bio, created_at }
Subset ์ญ์
- Subset ์ ํ
- [Delete] ๋ฒํผ ํด๋ฆญ
- ํ์ธ ๋ชจ๋ฌ์์ [Confirm] ํด๋ฆญ
์ฌ์ฉ ์ค์ธ Subset ์ญ์ : ์ญ์ ํ๋ ค๋ Subset์ ์ฌ์ฉํ๋ API๊ฐ ์๋ค๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
์ค์ ์์
์ฌ์ฉ์ ๊ด๋ฆฌ ์์คํ
// User Entity Subsets
// Subset A: ๋ชฉ๋ก์ฉ (์ต์ ์ ๋ณด)
{
id: true,
email: true,
name: true,
role: true,
is_active: true,
}
// Subset B: ์์ธ์ฉ (์ ์ฒด ์ ๋ณด, ๋ฏผ๊ฐ ์ ๋ณด ์ ์ธ)
{
id: true,
email: true,
name: true,
role: true,
bio: true,
profile_image: true,
phone: true,
is_active: true,
created_at: true,
updated_at: true,
}
// Subset C: ๊ด๋ฆฌ์์ฉ (๋ชจ๋ ์ ๋ณด)
{
...Subset B,
last_login_at: true,
login_count: true,
ip_address: true,
}
๋ธ๋ก๊ทธ ์์คํ
// Post Entity Subsets
// Subset A: ๋ชฉ๋ก์ฉ (์์ฝ)
{
id: true,
title: true,
excerpt: true,
author: "User.A",
view_count: true,
created_at: true,
}
// Subset B: ์์ธ์ฉ (์ ์ฒด ๋ด์ฉ)
{
id: true,
title: true,
content: true,
author: "User.B",
category: "Category.A",
tags: "Tag.A",
view_count: true,
created_at: true,
updated_at: true,
}
// Subset C: ๋๊ธ ํฌํจ
{
...Subset B,
comments: "Comment.A",
}
Model์์ ์ฌ์ฉ
Subset์ ์ ์ํ๋ฉด Model API์์ ์๋์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
findMany์์ ์ฌ์ฉ
class UserModelClass extends BaseModelClass {
@api({ httpMethod: "GET" })
async findMany(params: ListParams<User>) {
const { qb } = this.getSubsetQueries("A");
return this.executeSubsetQuery({
subset: "A",
qb,
params,
});
}
}
findById์์ ์ฌ์ฉ
class UserModelClass extends BaseModelClass {
@api({ httpMethod: "GET" })
async findById(id: number) {
const { qb } = this.getSubsetQueries("B");
qb.where("id", id);
return this.executeSubsetQuery({
subset: "B",
qb,
params: { num: 1, page: 1 },
}).then(result => result.rows[0]);
}
}
์ฑ๋ฅ ์ต์ ํ
ํ์ํ ํ๋๋ง ์ ํ
// โ ๋ชจ๋ ํ๋ ์กฐํ (๋๋ฆผ)
SELECT * FROM users
// โ
Subset A ์ฌ์ฉ (๋น ๋ฆ)
SELECT id, email, name FROM users
๊ด๊ณ ๋ก๋ฉ ์ต์ํ
// โ ๋ถํ์ํ ๊ด๊ณ ํฌํจ
{
posts: "Post.C", // Post์ ๋ชจ๋ ๊ด๊ณ๊น์ง ๋ก๋ฉ
}
// โ
ํ์ํ ๊ด๊ณ๋ง
{
posts: "Post.A", // Post์ ๊ธฐ๋ณธ ์ ๋ณด๋ง
}
๋ค์ ๋จ๊ณ