Scaffolding ํญ์์๋ Entity๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Model๊ณผ ํ
์คํธ ์ฝ๋๋ฅผ ์๋ ์์ฑํ ์ ์์ต๋๋ค. CLI์ pnpm scaffold ๋ช
๋ น์ด๋ฅผ ์๊ฐ์ ์ธํฐํ์ด์ค๋ก ์ ๊ณตํฉ๋๋ค.
Scaffolding ํญ ๊ตฌ์กฐ
Scaffolding ํญ์ ๋ ๊ฐ์ง ์ฃผ์ ์์ญ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค:
- ์ผ์ชฝ Sidebar: Entity ๋ชฉ๋ก๊ณผ ์ ํ ์ฒดํฌ๋ฐ์ค
- ์ค๋ฅธ์ชฝ Content: ์ฝ๋ ์์ฑ ์ต์
(Model Class, Model Test, View)
์์ฑ ๊ฐ๋ฅํ ์ฝ๋
| ์ฝ๋ ํ์
| ์ค๋ช
| ์ํ | CLI ๋ช
๋ น์ด |
|---|
| Model Class | Entity๋ฅผ ์ํ Model ํด๋์ค | โ
์ฌ์ฉ ๊ฐ๋ฅ | pnpm scaffold model |
| Model Test | Model ํ
์คํธ ํ์ผ | โ
์ฌ์ฉ ๊ฐ๋ฅ | pnpm scaffold model_test |
| View List | ๋ชฉ๋ก View ์ปดํฌ๋ํธ | ๐ง ๊ฐ๋ฐ ์ค | - |
| View Form | ํผ View ์ปดํฌ๋ํธ | ๐ง ๊ฐ๋ฐ ์ค | - |
View ์ปดํฌ๋ํธ ์์ฑ ๊ธฐ๋ฅ์ ํ์ฌ ๊ฐ๋ฐ ์ค์
๋๋ค.
Sonamu UI์ ๋ค๋ฅธ ๊ธฐ๋ฅ์ ํตํด React ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
Model ํด๋์ค ์์ฑ
1. Entity ์ ํ
์ผ์ชฝ Entity ๋ชฉ๋ก์์ Model์ ์์ฑํ Entity๋ฅผ ์ ํํฉ๋๋ค.
๋จ์ผ ์ ํ:
โ User
โก Post
โก Comment
๋ค์ค ์ ํ:
โ User
โ Post
โ Comment
2. ์์ฑ ์ต์
์ ํ
โ Model Class ์ฒดํฌ๋ฐ์ค๋ฅผ ์ ํํฉ๋๋ค.
3. Generate ์คํ
[Generate] ๋ฒํผ์ ํด๋ฆญํ๋ฉด ๋ค์ ํ์ผ์ด ์์ฑ๋ฉ๋๋ค:
๐src/models/
๐TSUser.model.ts - User Model ํด๋์ค
์์ฑ๋ ์ฝ๋
import { BaseModelClass } from "sonamu";
import type { InferSelectModel } from "sonamu";
import { UserEntity } from "../entities/User.entity";
import type { UserSubsetKey, UserSubsetMapping } from "../sonamu.generated";
import { userLoaderQueries, userSubsetQueries } from "../sonamu.generated.sso";
export type User = InferSelectModel<typeof UserEntity>;
class UserModelClass extends BaseModelClass<
UserSubsetKey,
UserSubsetMapping,
typeof userSubsetQueries,
typeof userLoaderQueries
> {
constructor() {
super("User", userSubsetQueries, userLoaderQueries);
}
// TODO: Model ๋ฉ์๋ ์ถ๊ฐ
}
export const UserModel = new UserModelClass();
์๋ ์์ฑ๋๋ ๊ธฐ๋ฅ:
- โ
TypeScript ํ์
์ ์
- โ
Entity ์ฐ๊ฒฐ
- โ
BaseModel ์์
- โ
๊ธฐ๋ณธ CRUD ๋ฉ์๋
Model ํ
์คํธ ์์ฑ
1. Entity ์ ํ
Model๊ณผ ๋์ผํ๊ฒ Entity๋ฅผ ์ ํํฉ๋๋ค.
2. ์์ฑ ์ต์
์ ํ
โ Model Test ์ฒดํฌ๋ฐ์ค๋ฅผ ์ ํํฉ๋๋ค.
Model๊ณผ Test ๋์ ์์ฑ: Model Class์ Model Test๋ฅผ ๋์์ ์ ํํ์ฌ ํ ๋ฒ์ ์์ฑํ ์ ์์ต๋๋ค.
3. Generate ์คํ
[Generate] ๋ฒํผ์ ํด๋ฆญํ๋ฉด ๋ค์ ํ์ผ์ด ์์ฑ๋ฉ๋๋ค:
๐src/models/
๐TSUser.model.test.ts - User Model ํ
์คํธ
์์ฑ๋ ์ฝ๋
src/models/User.model.test.ts
import { beforeAll, describe, test } from "bun:test";
import { expect } from "@jest/globals";
import { FixtureManager } from "sonamu/test";
import { UserModel } from "./User.model";
describe("User Model", () => {
beforeAll(async () => {
await FixtureManager.sync();
});
test("findById", async () => {
const user = await UserModel.findById(1);
expect(user).toBeDefined();
expect(user?.id).toBe(1);
});
test("findMany", async () => {
const users = await UserModel.findMany({
num: 10,
page: 1,
});
expect(users.rows.length).toBeGreaterThan(0);
});
// TODO: ์ถ๊ฐ ํ
์คํธ ์์ฑ
});
์๋ ์์ฑ๋๋ ํ
์คํธ:
- โ
findById: ID๋ก ๋จ์ผ ๋ ์ฝ๋ ์กฐํ
- โ
findMany: ๋ชฉ๋ก ์กฐํ (ํ์ด์ง๋ค์ด์
)
์ผ๊ด ์์ฑ
๋ชจ๋ Entity์ ๋ํด ์์ฑ
- [Select All] ๋ฒํผ ํด๋ฆญ
- ์์ฑ ์ต์
์ ํ
- [Generate] ํด๋ฆญ
๊ฒฐ๊ณผ:
โ User.model.ts created
โ User.model.test.ts created
โ Post.model.ts created
โ Post.model.test.ts created
โ Comment.model.ts created
โ Comment.model.test.ts created
6 files generated successfully!
ํน์ Entity๋ง ์ ํ
ํ๋ก์ ํธ ์ด๊ธฐ ์ค์ ์ ๋ชจ๋ Entity์ ๋ํด:
โ User
โ Post
โ Comment
โ Category
โ Tag
[Generate] โ 10๊ฐ ํ์ผ ์์ฑ
์ Entity ์ถ๊ฐ ์ ํด๋น Entity๋ง:
โก User (์ด๋ฏธ ์์ฑ๋จ)
โก Post (์ด๋ฏธ ์์ฑ๋จ)
โ Product (์ ๊ท)
[Generate] โ 2๊ฐ ํ์ผ ์์ฑ
์์ฑ ๊ฒฐ๊ณผ ํ์ธ
์ฑ๊ณต ๋ฉ์์ง
โ
Code Generation Complete
Generated files:
โ src/models/User.model.ts
โ src/models/User.model.test.ts
โ src/models/Post.model.ts
โ src/models/Post.model.test.ts
Total: 4 files
ํ์ผ ์ถฉ๋
์ด๋ฏธ ์กด์ฌํ๋ ํ์ผ์ ์์ฑํ๋ ค๊ณ ํ๋ฉด ํ์ธ ๋ชจ๋ฌ์ด ํ์๋ฉ๋๋ค:
โ ๏ธ Files Already Exist
The following files will be overwritten:
โข src/models/User.model.ts
โข src/models/User.model.test.ts
[Cancel] [Backup & Overwrite] [Overwrite]
์ ํ ์ต์
:
- Cancel: ์์ฑ ์ทจ์
- Backup & Overwrite: ๊ธฐ์กด ํ์ผ์
.bak๋ก ๋ฐฑ์
ํ ๋ฎ์ด์ฐ๊ธฐ
- Overwrite: ๋ฐ๋ก ๋ฎ์ด์ฐ๊ธฐ (์ฃผ์!)
์ฝ๋ ์์ค ์ฃผ์: ๊ธฐ์กด ํ์ผ์ ๋ฎ์ด์ฐ๋ฉด ์์ฑํ ๋น์ฆ๋์ค ๋ก์ง์ด ์ญ์ ๋ ์ ์์ต๋๋ค.
์ปค์คํฐ๋ง์ด์งํ Model์ ๋ฐฑ์
ํ๊ฑฐ๋ ๋ฎ์ด์ฐ๊ธฐ๋ฅผ ํผํ์ธ์.
View ์์ฑ (๊ฐ๋ฐ ์ค)
View ์ปดํฌ๋ํธ ์๋ ์์ฑ ๊ธฐ๋ฅ์ ํ์ฌ ๊ฐ๋ฐ ์ค์
๋๋ค.
๋์: Sonamu UI์ ๋ค๋ฅธ ๊ธฐ๋ฅ ์ฌ์ฉ
ํ์ฌ๋ ๋ค์ ๋ฐฉ๋ฒ์ผ๋ก View๋ฅผ ๊ด๋ฆฌํ ์ ์์ต๋๋ค:
- Entity ๊ธฐ๋ฐ ์๋ ์์ฑ: Entity๋ฅผ ์์ฑํ๋ฉด ๊ธฐ๋ณธ View ํ
ํ๋ฆฟ์ด ์ ๊ณต๋ฉ๋๋ค
- ์๋ ์์ฑ: React ์ปดํฌ๋ํธ๋ฅผ ์ง์ ์์ฑํฉ๋๋ค
- ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ:
@sonamu-kit/react-components ํ์ฉ
View List์ View Form ์์ฑ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋๋ฉด ์ด ๋ฌธ์๊ฐ ์
๋ฐ์ดํธ๋ฉ๋๋ค.
์์ฑ ํ ์ํฌํ๋ก์ฐ
1. Model ๋ฉ์๋ ์ถ๊ฐ
์์ฑ๋ Model์ ๋น์ฆ๋์ค ๋ก์ง์ ์ถ๊ฐํฉ๋๋ค:
class UserModelClass extends BaseModelClass<
UserSubsetKey,
UserSubsetMapping,
typeof userSubsetQueries,
typeof userLoaderQueries
> {
constructor() {
super("User", userSubsetQueries, userLoaderQueries);
}
// ์ด๋ฉ์ผ๋ก ์ฌ์ฉ์ ์ฐพ๊ธฐ
async findByEmail(email: string): Promise<User | null> {
return this.getPuri("r")
.where("email", email)
.first();
}
// ํ์ฑ ์ฌ์ฉ์๋ง ์กฐํ
async findActiveUsers() {
return this.getPuri("r")
.where("is_active", true)
.where("deleted_at", null);
}
}
2. ํ
์คํธ ์ถ๊ฐ
์์ฑ๋ ํ
์คํธ ํ์ผ์ ์ถ๊ฐ ํ
์คํธ๋ฅผ ์์ฑํฉ๋๋ค:
src/models/User.model.test.ts
describe("User Model - Extended", () => {
test("findByEmail", async () => {
const user = await UserModel.findByEmail("[email protected]");
expect(user).toBeDefined();
expect(user?.email).toBe("[email protected]");
});
test("findActiveUsers", async () => {
const users = await UserModel.findActiveUsers();
users.forEach(user => {
expect(user.is_active).toBe(true);
});
});
});
3. API ์ถ๊ฐ
Model์ @api ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ API ์๋ํฌ์ธํธ๋ฅผ ์ถ๊ฐํฉ๋๋ค:
class UserModelClass extends BaseModelClass<
UserSubsetKey,
UserSubsetMapping,
typeof userSubsetQueries,
typeof userLoaderQueries
> {
constructor() {
super("User", userSubsetQueries, userLoaderQueries);
}
@api({ httpMethod: "GET" })
async findActiveUsers() {
const { qb } = this.getSubsetQueries("A");
qb.where("is_active", true);
return this.executeSubsetQuery({
subset: "A",
qb,
params: { num: 20, page: 1 },
});
}
}
์ค์ ํ
1. ํ๋ก์ ํธ ์ด๊ธฐ ์ค์
1. ๋ชจ๋ Entity ์ ์
โ
2. Scaffolding ํญ์์ ์ผ๊ด ์์ฑ
- [Select All]
- Model Class โ
- Model Test โ
- [Generate]
โ
3. ๊ฐ Model์ ๋น์ฆ๋์ค ๋ก์ง ์ถ๊ฐ
2. ์ Entity ์ถ๊ฐ ์
1. Entity ํญ์์ Entity ์์ฑ
โ
2. Migration ํญ์์ ๋ง์ด๊ทธ๋ ์ด์
์คํ
โ
3. Scaffolding ํญ์์ ํด๋น Entity๋ง ์์ฑ
โ
4. ๋น์ฆ๋์ค ๋ก์ง ๋ฐ ํ
์คํธ ์์ฑ
3. ์ฌ์์ฑ์ด ํ์ํ ๊ฒฝ์ฐ
Entity ๊ตฌ์กฐ๊ฐ ํฌ๊ฒ ๋ณ๊ฒฝ๋์ด Model์ ์ฌ์์ฑํด์ผ ํ๋ ๊ฒฝ์ฐ:
# ๊ธฐ์กด ํ์ผ ๋ฐฑ์
cp src/models/User.model.ts src/models/User.model.ts.bak
# UI์์ ์ฌ์์ฑ
[Backup & Overwrite]
# ๋ฐฑ์
ํ์ผ์์ ์ปค์คํ
๋ก์ง ๋ณต์
๋ค์ ๋จ๊ณ