Enum์ ๋ฏธ๋ฆฌ ์ ์๋ ๊ฐ ๋ชฉ๋ก ์ค ํ๋๋ง ์ ํํ ์ ์๋ ์ด๊ฑฐํ ํ์
์
๋๋ค. ํ์
์์ ์ฑ์ ์ ๊ณตํ๊ณ ์ฌ์ฉ์ ์ธํฐํ์ด์ค์์ ์ ํ ์ต์
์ ์ฝ๊ฒ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
Enum์ด๋?
Enum์ ์ ํ๋ ๊ฐ์ ์งํฉ์ ์ ์ํ์ฌ ๋ค์์ ์ ๊ณตํฉ๋๋ค:
ํ์
์์ ์ฑ
์ ์๋์ง ์์ ๊ฐ ์
๋ ฅ ๋ฐฉ์งTypeScript์์ Union ํ์
์ผ๋ก ์๋ ๋ณํ
UI ์๋ ์์ฑ
์ ํ ๋ชฉ๋ก ์๋ ๊ตฌ์ฑSelect, ButtonSet ์ปดํฌ๋ํธ์ ์ฆ์ ์ฌ์ฉ
๋ ์ด๋ธ ๊ด๋ฆฌ
ํค์ ํ์๋ช
๋ถ๋ฆฌ๋ค๊ตญ์ด ์ง์ ์ฉ์ด
์ ์ง๋ณด์์ฑ
์ค์ ์ง์ค์ ๊ด๋ฆฌ๊ฐ ๋ณ๊ฒฝ ์ ํ ๊ณณ๋ง ์์
Enum ์ ์ํ๊ธฐ
entity.json์์ ์ ์
Entity์ enums ์น์
์ ํค-๋ ์ด๋ธ ์์ผ๋ก ์ ์ํฉ๋๋ค.
{
"id": "User",
"props": [
{
"name": "role",
"type": "enum",
"id": "UserRole",
"desc": "์ฌ์ฉ์ ์ญํ "
},
{
"name": "status",
"type": "enum",
"id": "UserStatus",
"desc": "๊ณ์ ์ํ"
}
],
"enums": {
"UserRole": {
"admin": "๊ด๋ฆฌ์",
"normal": "์ผ๋ฐ ์ฌ์ฉ์",
"guest": "๊ฒ์คํธ"
},
"UserStatus": {
"active": "ํ์ฑ",
"inactive": "๋นํ์ฑ",
"suspended": "์ ์ง",
"deleted": "์ญ์ ๋จ"
}
}
}
๊ตฌ์กฐ:
- Enum ID: PascalCase (์:
UserRole, PostStatus)
- Key: ์๋ฌธ์, ์ซ์, ์ธ๋์ค์ฝ์ด (์:
admin, draft_saved)
- Label: ํ์์ฉ ํ
์คํธ, ํ๊ธ ๊ฐ๋ฅ (์: โ๊ด๋ฆฌ์โ, โ์์์ ์ฅโ)
Sonamu UI์์ ์ ์
Entity ํธ์ง ํ์ด์ง๋ก ์ด๋
Sonamu UI์์ Entity๋ฅผ ์ ํํฉ๋๋ค.
Enums ์น์
์ผ๋ก ์คํฌ๋กค
Props, Indexes, Subsets ์๋์ Enums ์น์
์ด ์์ต๋๋ค.
Add Enum ํด๋ฆญ
์ Enum์ ์ถ๊ฐํฉ๋๋ค.Enum ID ์
๋ ฅ:
- PascalCase๋ก ์
๋ ฅ
- Entity์ ์ฐ๊ด์ํค๋ ค๋ฉด
{Entity} ํจํด ์ฌ์ฉ
- ์:
$ModelRole โ UserRole (์๋ ๋ณํ)
Enum ๊ฐ ์ถ๊ฐ
๊ฐ Enum์ ๋ณ๋ ํญ์ผ๋ก ํ์๋๋ฉฐ, โAdd Rowโ ๋ฒํผ์ผ๋ก ํค-๋ ์ด๋ธ ์์ ์ถ๊ฐํฉ๋๋ค.
- Key: ์๋ฌธ ์๋ฌธ์, ์ซ์, ์ธ๋์ค์ฝ์ด
- Label: ํ๊ธ ๋๋ ํ์๋ช
์ ์ฅ
Entity๋ฅผ ์ ์ฅํ๋ฉด Enum์ด ํจ๊ป ์ ์ฅ๋ฉ๋๋ค.
๐ธ ํ์: Sonamu UI์ Enums ์น์
- ์ฌ๋ฌ Enum์ด ํญ์ผ๋ก ๊ตฌ๋ถ๋์ด ํ์
์๋ ์์ฑ๋๋ ์ฝ๋
Enum์ ์ ์ํ๋ฉด Sonamu๊ฐ ์๋์ผ๋ก ๋ค์์ ์์ฑํฉ๋๋ค:
1. Zod ์คํค๋ง
import { z } from "zod";
// Enum ์คํค๋ง
export const UserRole = z.enum(["admin", "normal", "guest"]);
// Enum ๋ ์ด๋ธ
export const UserRoleLabels = {
admin: "๊ด๋ฆฌ์",
normal: "์ผ๋ฐ ์ฌ์ฉ์",
guest: "๊ฒ์คํธ",
} as const;
2. TypeScript ํ์
import { UserRole } from "./sonamu.generated";
// Union ํ์
์ผ๋ก ์ถ๋ก
export type UserRole = z.infer<typeof UserRole>;
// ๊ฒฐ๊ณผ: "admin" | "normal" | "guest"
3. ๋ ์ด๋ธ ํฌํผ ํจ์
// ๋ ์ด๋ธ ๊ฐ์ ธ์ค๊ธฐ ํจ์
export function getUserRoleLabel(role: UserRole): string {
return UserRoleLabels[role];
}
Enum ์ฌ์ฉํ๊ธฐ
Props์์ ์ฌ์ฉ
{
"props": [
{
"name": "role",
"type": "enum",
"id": "UserRole",
"desc": "์ฌ์ฉ์ ์ญํ ",
"dbDefault": "normal"
}
]
}
๋ฐ์ดํฐ๋ฒ ์ด์ค:
- ์ปฌ๋ผ ํ์
:
text
- ์ ์ฅ ๊ฐ: Key ๊ฐ (์:
"admin")
TypeScript:
type User = {
id: number;
role: "admin" | "normal" | "guest"; // Union ํ์
};
API์์ ์ฌ์ฉ
import { UserRole } from "./user.types";
export class UserModel extends BaseModel {
@api({ httpMethod: "POST" })
async updateRole(userId: number, role: UserRole) {
// role์ ํ์
์์ ํจ
await this.puri()
.where("id", userId)
.update({ role });
return { success: true };
}
}
๋ ์ด๋ธ ํ์
import { getUserRoleLabel } from "./sonamu.generated";
const user = await UserModel.findById(1);
const roleLabel = getUserRoleLabel(user.role);
// "๊ด๋ฆฌ์"
์์ฃผ ์ฌ์ฉ๋๋ Enum ํจํด
1. OrderBy Enum
์ ๋ ฌ ์ต์
์ ์ ์ํฉ๋๋ค.
{
"enums": {
"UserOrderBy": {
"id-desc": "ID ์ต์ ์",
"id-asc": "ID ์ค๋๋์",
"created_at-desc": "๋ฑ๋ก์ผ ์ต์ ์",
"created_at-asc": "๋ฑ๋ก์ผ ์ค๋๋์",
"username-asc": "์ด๋ฆ์"
}
}
}
ํ์ฉ:
async findAll(orderBy: UserOrderBy = "id-desc") {
const [field, direction] = orderBy.split("-");
return this.puri()
.orderBy(field, direction as "asc" | "desc")
.many();
}
2. SearchField Enum
๊ฒ์ ๊ฐ๋ฅํ ํ๋๋ฅผ ์ ์ํฉ๋๋ค.
{
"enums": {
"UserSearchField": {
"email": "์ด๋ฉ์ผ",
"username": "์ด๋ฆ",
"phone": "์ ํ๋ฒํธ"
}
}
}
ํ์ฉ:
async search(field: UserSearchField, keyword: string) {
return this.puri()
.whereLike(field, `%${keyword}%`)
.many();
}
3. Status Enum
์ํ๋ฅผ ์ ์ํฉ๋๋ค.
{
"enums": {
"PostStatus": {
"draft": "์์์ ์ฅ",
"published": "๋ฐํ๋จ",
"archived": "๋ณด๊ด๋จ",
"deleted": "์ญ์ ๋จ"
}
}
}
ํ์ฉ:
async publish(postId: number) {
await this.puri()
.where("id", postId)
.update({ status: "published" });
}
4. Type/Category Enum
๋ถ๋ฅ๋ฅผ ์ ์ํฉ๋๋ค.
{
"enums": {
"NotificationType": {
"email": "์ด๋ฉ์ผ",
"sms": "๋ฌธ์๋ฉ์์ง",
"push": "ํธ์ ์๋ฆผ",
"in_app": "์ธ์ฑ ์๋ฆผ"
}
}
}
Enum ๋ฐฐ์ด ํ์
์ฌ๋ฌ Enum ๊ฐ์ ๋ฐฐ์ด๋ก ์ ์ฅํ ์ ์์ต๋๋ค.
{
"props": [
{
"name": "permissions",
"type": "enum[]",
"id": "Permission",
"desc": "๊ถํ ๋ชฉ๋ก"
}
],
"enums": {
"Permission": {
"read": "์ฝ๊ธฐ",
"write": "์ฐ๊ธฐ",
"delete": "์ญ์ ",
"admin": "๊ด๋ฆฌ์"
}
}
}
๋ฐ์ดํฐ๋ฒ ์ด์ค:
- ์ปฌ๋ผ ํ์
:
text[]
- ์ ์ฅ ๊ฐ:
["read", "write"]
TypeScript:
type User = {
id: number;
permissions: ("read" | "write" | "delete" | "admin")[];
};
ํ์ฉ:
// ๊ถํ ์ฒดํฌ
function hasPermission(user: User, permission: Permission): boolean {
return user.permissions.includes(permission);
}
// ๊ถํ ์ถ๊ฐ
async grantPermission(userId: number, permission: Permission) {
const user = await this.findById(userId);
if (!user.permissions.includes(permission)) {
await this.puri()
.where("id", userId)
.update({
permissions: [...user.permissions, permission]
});
}
}
ํ๋ก ํธ์๋์์ Enum ์ฌ์ฉ
Select ์ปดํฌ๋ํธ
import { UserRoleSelect } from "@/components/UserRoleSelect";
function UserForm() {
const [role, setRole] = useState<UserRole>("normal");
return (
<UserRoleSelect
value={role}
onChange={setRole}
/>
);
}
import { UserStatusButtonSet } from "@/components/UserStatusButtonSet";
function StatusFilter() {
const [status, setStatus] = useState<UserStatus | null>(null);
return (
<UserStatusButtonSet
value={status}
onChange={setStatus}
allowNull // ์ ํ ํด์ ๊ฐ๋ฅ
/>
);
}
Enum ๊ฒ์ฆ
Zod๋ฅผ ์ฌ์ฉํ์ฌ ์๋์ผ๋ก Enum ๊ฐ์ ๊ฒ์ฆํฉ๋๋ค.
import { UserRole } from "./sonamu.generated";
export const UpdateRoleParams = z.object({
userId: z.number(),
role: UserRole, // ์๋ ๊ฒ์ฆ
});
// ์๋ชป๋ ๊ฐ ์
๋ ฅ ์
UpdateRoleParams.parse({
userId: 1,
role: "invalid_role" // Error!
});
Enum ๋ค์ด๋ฐ ๊ท์น
๊ถ์ฅ ํจํด
| ์ฉ๋ | ํจํด | ์์ |
|---|
| Entity ์ํ | {Entity}Status | PostStatus, OrderStatus |
| Entity ํ์
| {Entity}Type | NotificationType, PaymentType |
| Entity ์ญํ | {Entity}Role | UserRole, MemberRole |
| ์ ๋ ฌ ์ต์
| {Entity}OrderBy | UserOrderBy, PostOrderBy |
| ๊ฒ์ ํ๋ | {Entity}SearchField | UserSearchField |
| ์นดํ
๊ณ ๋ฆฌ | {Entity}Category | ProductCategory |
| ๊ถํ | {Entity}Permission | UserPermission |
$Model ํจํด
Entity ์ด๋ฆ์ ๋์ ์ผ๋ก ํฌํจํ๋ ค๋ฉด $Model์ ์ฌ์ฉํฉ๋๋ค:
{
"enums": {
"$ModelRole": {
"admin": "๊ด๋ฆฌ์",
"normal": "์ผ๋ฐ"
},
"$ModelStatus": {
"active": "ํ์ฑ",
"inactive": "๋นํ์ฑ"
}
}
}
๋ณํ ๊ฒฐ๊ณผ:
User Entity โ UserRole, UserStatus
Post Entity โ PostRole, PostStatus
์ฃผ์์ฌํญ
Enum ๊ฐ ๋ณ๊ฒฝ ์ ์ฃผ์์ด๋ฏธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ Enum ํค๋ฅผ ๋ณ๊ฒฝํ๋ฉด ๊ธฐ์กด ๋ฐ์ดํฐ์ ๋ถ์ผ์น๊ฐ ๋ฐ์ํฉ๋๋ค.๋ณ๊ฒฝ ๋ฐฉ๋ฒ:
- ์ ํค ์ถ๊ฐ
- ๋ฐ์ดํฐ ๋ง์ด๊ทธ๋ ์ด์
(๊ธฐ์กด ํค โ ์ ํค)
- ๊ตฌ ํค ์ญ์
Key ๋ค์ด๋ฐ ์ ํEnum Key๋ ๋ค์๋ง ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค:
- ์๋ฌธ์ (a-z)
- ์ซ์ (0-9)
- ์ธ๋์ค์ฝ์ด (_)
ํ์ดํ(-)์ ์ฌ์ฉ ๋ถ๊ฐํฉ๋๋ค.
๋ ์ด๋ธ ๋ณ๊ฒฝ์ ์์ ๋กญ๊ฒLabel์ ํ์์ฉ์ด๋ฏ๋ก ์ธ์ ๋ ์ง ๋ณ๊ฒฝ ๊ฐ๋ฅํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค์๋ Key๋ง ์ ์ฅ๋ฉ๋๋ค.
Enum vs ๋ณ๋ ํ
์ด๋ธ
| ๊ธฐ์ค | Enum | ๋ณ๋ ํ
์ด๋ธ |
|---|
| ๊ฐ ๊ฐ์ | ์ ์ (< 20๊ฐ) | ๋ง์ (> 20๊ฐ) |
| ๋ณ๊ฒฝ ๋น๋ | ๊ฑฐ์ ์์ | ์์ฃผ ๋ณ๊ฒฝ |
| ์ถ๊ฐ ์ ๋ณด | ๋ถํ์ | ํ์ (์ค๋ช
, ์์ ๋ฑ) |
| ์ฑ๋ฅ | ๋น ๋ฆ (JOIN ๋ถํ์) | ๋๋ฆผ (JOIN ํ์) |
| ๊ถ์ฅ ์ฌ์ฉ | ์ํ, ์ญํ , ํ์
| ์นดํ
๊ณ ๋ฆฌ, ์ฝ๋ ํ
์ด๋ธ |
Enum ์ฌ์ฉ ์์:
- ์ฌ์ฉ์ ์ญํ (admin, user, guest)
- ๊ฒ์๊ธ ์ํ (draft, published, deleted)
- ์๋ฆผ ํ์
(email, sms, push)
๋ณ๋ ํ
์ด๋ธ ์ฌ์ฉ ์์:
- ์ง์ญ ๋ชฉ๋ก (์์ธ, ๋ถ์ฐ, โฆ)
- ์ํ ์นดํ
๊ณ ๋ฆฌ (๊ณ์ธต ๊ตฌ์กฐ)
- ๊ตญ๊ฐ ์ฝ๋ (์ถ๊ฐ ์ ๋ณด ๋ง์)
๋ค์ ๋จ๊ณ