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μ΄ ν¨κ» μ μ₯λ©λλ€.
μλ μμ±λλ μ½λ
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)
λ³λ ν
μ΄λΈ μ¬μ© μμ:
- μ§μ λͺ©λ‘ (μμΈ, λΆμ°, β¦)
- μν μΉ΄ν
κ³ λ¦¬ (κ³μΈ΅ ꡬ쑰)
- κ΅κ° μ½λ (μΆκ° μ 보 λ§μ)
λ€μ λ¨κ³