findByIdλ IDλ‘ λ¨μΌ λ μ½λλ₯Ό μ‘°ννλ λ©μλμ
λλ€. μ§μ λ μλΈμ
μΌλ‘ λ°μ΄ν°λ₯Ό λ‘λνλ©°, λ μ½λκ° μμΌλ©΄ NotFoundExceptionμ λ°μμν΅λλ€.
findByIdλ BaseModelClassμ μ μλμ΄ μμ§ μμ΅λλ€. Entityλ₯Ό μμ±νλ©΄ Syncerκ° κ° Model ν΄λμ€μ μλμΌλ‘ μμ±νλ νμ€ ν¨ν΄μ
λλ€.
νμ
μκ·Έλμ²
async findById<T extends SubsetKey>(
subset: T,
id: number
): Promise<SubsetMapping[T]>
μλ μμ± μ½λ
Sonamuλ Entityλ₯Ό κΈ°λ°μΌλ‘ λ€μ μ½λλ₯Ό μλμΌλ‘ μμ±ν©λλ€:
// src/application/user/user.model.ts (μλ μμ±)
class UserModelClass extends BaseModelClass {
@api({ httpMethod: "GET", clients: ["axios", "tanstack-query"], resourceName: "User" })
async findById<T extends UserSubsetKey>(
subset: T,
id: number
): Promise<UserSubsetMapping[T]> {
const { rows } = await this.findMany(subset, {
id,
num: 1,
page: 1,
});
if (!rows[0]) {
throw new NotFoundException(`μ‘΄μ¬νμ§ μλ User ID ${id}`);
}
return rows[0];
}
}
λ΄λΆ λμ:
findManyλ₯Ό νΈμΆνμ¬ IDλ‘ μ‘°ν
num: 1, page: 1λ‘ λ¨κ±΄λ§ κ°μ Έμ΄
- κ²°κ³Όκ° μμΌλ©΄
NotFoundException λ°μ
- 첫 λ²μ§Έ λ μ½λ λ°ν
λ§€κ°λ³μ
μ‘°νν λ°μ΄ν°μ μλΈμ
μ μ§μ ν©λλ€.
νμ
: SubsetKey (μ: "A", "B", "C")
μλΈμ
μ Entity μ μμμ μ€μ ν λ°μ΄ν° ννλ₯Ό κ²°μ ν©λλ€. κ° μλΈμ
μ λ€λ₯Έ νλμ κ΄κ³λ₯Ό ν¬ν¨ν μ μμ΅λλ€.
// κΈ°λ³Έ μ λ³΄λ§ μ‘°ν
const user = await UserModel.findById("A", 1);
// κ΄κ³ λ°μ΄ν° ν¬ν¨ μ‘°ν
const user = await UserModel.findById("B", 1);
μ‘°νν λ μ½λμ IDμ
λλ€.
νμ
: number
const user = await UserModel.findById("A", 123);
λ°νκ°
νμ
: Promise<SubsetMapping[T]>
μ§μ λ μλΈμ
νμ
μ λ μ½λλ₯Ό λ°νν©λλ€. νμ
μ μλΈμ
μ λ°λΌ μλμΌλ‘ μΆλ‘ λ©λλ€.
// userμ νμ
μ μλμΌλ‘ UserSubsetMapping["A"]λ‘ μΆλ‘ λ¨
const user = await UserModel.findById("A", 1);
console.log(user.id); // number
console.log(user.email); // string
console.log(user.name); // string
NotFoundException
IDμ ν΄λΉνλ λ μ½λκ° μμΌλ©΄ NotFoundExceptionμ΄ λ°μν©λλ€.
try {
const user = await UserModel.findById("A", 999);
} catch (error) {
if (error instanceof NotFoundException) {
console.error("μ¬μ©μλ₯Ό μ°Ύμ μ μμ΅λλ€");
}
}
HTTP μν μ½λ: 404
κΈ°λ³Έ μ¬μ©λ²
λ¨μ μ‘°ν
import { UserModel } from "./user/user.model";
class UserService {
async getUser(userId: number) {
// IDλ‘ μ¬μ©μ μ‘°ν (μλΈμ
A)
const user = await UserModel.findById("A", userId);
return {
id: user.id,
email: user.email,
name: user.name
};
}
}
APIμμ μ¬μ©
findByIdλ μλμΌλ‘ @api λ°μ½λ μ΄ν°κ° μ μ©λμ΄ REST APIλ‘ λ
ΈμΆλ©λλ€:
// μλ μμ±λ μ½λ
@api({ httpMethod: "GET", clients: ["axios", "tanstack-query"], resourceName: "User" })
async findById<T extends UserSubsetKey>(
subset: T,
id: number
): Promise<UserSubsetMapping[T]> {
// ...
}
μμ±λ ν΄λΌμ΄μΈνΈ μ½λ:
// services.generated.ts (μλ μμ±)
import { UserService } from "@/services/UserService";
// IDλ‘ μ¬μ©μ μ‘°ν
const user = await UserService.getUser("A", 123);
μλΈμ
λ³ μ¬μ©
μλΈμ
A (κΈ°λ³Έ)
const user = await UserModel.findById("A", 1);
// μ¬μ© κ°λ₯ν νλ
user.id; // number
user.email; // string
user.name; // string
user.created_at;// Date
μλΈμ
B (κ΄κ³ ν¬ν¨)
const user = await UserModel.findById("B", 1);
// κ΄κ³ λ°μ΄ν° μλ λ‘λ
user.id; // number
user.email; // string
user.name; // string
user.posts; // Post[] (1:N κ΄κ³)
user.profile; // Profile (1:1 κ΄κ³)
μλΈμ
C (μ€μ²© κ΄κ³)
const user = await UserModel.findById("C", 1);
// μ€μ²© κ΄κ³κΉμ§ λ‘λ
user.posts[0].comments; // Comment[] (μ€μ²© κ΄κ³)
user.profile.images; // Image[] (μ€μ²© κ΄κ³)
μ€μ μμ
μ¬μ©μ νλ‘ν
μ£Όλ¬Έ μμΈ
κΆν νμΈ
μλ¬ μ²λ¦¬
import { UserModel } from "./user/user.model";
import { api } from "sonamu";
class ProfileFrame {
@api({ httpMethod: "GET" })
async getProfile(userId: number) {
// IDλ‘ μ¬μ©μ μ‘°ν (νλ‘ν μ 보 ν¬ν¨)
const user = await UserModel.findById("Profile", userId);
return {
id: user.id,
email: user.email,
name: user.name,
avatar: user.profile?.avatar_url,
bio: user.profile?.bio,
posts_count: user.posts?.length ?? 0
};
}
}
import { OrderModel } from "./order/order.model";
import { api } from "sonamu";
class OrderFrame {
@api({ httpMethod: "GET" })
async getOrderDetail(orderId: number) {
// μ£Όλ¬Έ μμΈ μ‘°ν (μν, λ°°μ‘ μ 보 ν¬ν¨)
const order = await OrderModel.findById("Detail", orderId);
return {
id: order.id,
status: order.status,
total_amount: order.total_amount,
items: order.items.map(item => ({
product_name: item.product.name,
quantity: item.quantity,
price: item.price
})),
shipping: {
address: order.shipping_address,
status: order.shipping_status,
tracking_number: order.tracking_number
},
customer: {
name: order.user.name,
email: order.user.email
}
};
}
}
import { UserModel } from "./user/user.model";
import { Sonamu, api, UnauthorizedException } from "sonamu";
class PostFrame {
@api({ httpMethod: "POST" })
async deletePost(postId: number) {
const { user } = Sonamu.getContext();
// κ²μλ¬Ό μμ±μ νμΈ
const post = await PostModel.findById("A", postId);
if (post.user_id !== user.id) {
throw new UnauthorizedException("λ³ΈμΈμ κ²μλ¬Όλ§ μμ ν μ μμ΅λλ€");
}
await PostModel.del([postId]);
return { success: true };
}
}
import { UserModel } from "./user/user.model";
import { NotFoundException, api } from "sonamu";
class UserFrame {
@api({ httpMethod: "GET" })
async getUserSafely(userId: number) {
try {
// IDλ‘ μ¬μ©μ μ‘°ν
const user = await UserModel.findById("A", userId);
return {
exists: true,
user: {
id: user.id,
name: user.name,
email: user.email
}
};
} catch (error) {
if (error instanceof NotFoundException) {
return {
exists: false,
user: null
};
}
throw error;
}
}
@api({ httpMethod: "GET" })
async getMultipleUsers(userIds: number[]) {
const users = [];
for (const id of userIds) {
try {
const user = await UserModel.findById("A", id);
users.push(user);
} catch (error) {
// μ‘΄μ¬νμ§ μλ μ¬μ©μλ 건λλ
if (error instanceof NotFoundException) {
continue;
}
throw error;
}
}
return users;
}
}
findById vs findOne vs findMany
findById
- IDλ‘ λ¨μΌ λ μ½λ μ‘°ν
- λ μ½λκ° μμΌλ©΄ μμΈ λ°μ
- κ°μ₯ κ°λ¨νκ³ λΉ λ¦
- μλ μμ±λ¨
// IDλ‘ μ‘°ν (μμΌλ©΄ μμΈ)
const user = await UserModel.findById("A", 1);
findOne
- 쑰건μΌλ‘ λ¨μΌ λ μ½λ μ‘°ν
- λ μ½λκ° μμΌλ©΄ null λ°ν
- 볡μ‘ν 쑰건 κ°λ₯
- μ§μ ꡬν νμ (μ νμ )
// 쑰건μΌλ‘ μ‘°ν (μμΌλ©΄ null)
const user = await UserModel.findOne("A", {
email: "[email protected]"
});
findMany
- 쑰건μΌλ‘ μ¬λ¬ λ μ½λ μ‘°ν
- νμ΄μ§λ€μ΄μ
μ§μ
- μ΄ κ°μ λ°ν
- μλ μμ±λ¨
// 리μ€νΈ μ‘°ν (νμ΄μ§λ€μ΄μ
)
const { rows, total } = await UserModel.findMany("A", {
status: "active",
num: 20,
page: 1
});
νμ
μμ μ±
μλΈμ
μ λ°λΌ λ°ν νμ
μ΄ μλμΌλ‘ μΆλ‘ λ©λλ€:
// μλΈμ
A: κΈ°λ³Έ νλλ§
const userA = await UserModel.findById("A", 1);
userA.posts; // β νμ
μλ¬: Property 'posts' does not exist
// μλΈμ
B: posts ν¬ν¨
const userB = await UserModel.findById("B", 1);
userB.posts; // β
Post[]
ν΄λΌμ΄μΈνΈ μ¬μ©
React (TanStack Query)
import { useQuery } from "@tanstack/react-query";
import { UserService } from "@/services/UserService";
function UserProfile({ userId }: { userId: number }) {
const { data: user, isLoading, error } = useQuery({
queryKey: ["user", userId],
queryFn: () => UserService.getUser("A", userId)
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>User not found</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
import { UserService } from "@/services/UserService";
export default {
data() {
return {
user: null,
loading: false,
error: null
};
},
async mounted() {
this.loading = true;
try {
this.user = await UserService.getUser("A", this.userId);
} catch (error) {
this.error = error.message;
} finally {
this.loading = false;
}
}
};
μ£Όμμ¬ν
1. μλΈμ
μ ν
νμν λ°μ΄ν°λ§ ν¬ν¨νλ μλΈμ
μ μ ννμΈμ. λΆνμν κ΄κ³λ₯Ό λ‘λνλ©΄ μ±λ₯μ΄ μ νλ©λλ€.
// β λμ μ: λͺ¨λ κ΄κ³ λ‘λ
const user = await UserModel.findById("Full", 1);
// β
μ’μ μ: νμν νλλ§
const user = await UserModel.findById("A", 1);
2. μμΈ μ²λ¦¬
findByIdλ λ μ½λκ° μμΌλ©΄ μμΈλ₯Ό λ°μμν΅λλ€. νμν κ²½μ° μμΈ μ²λ¦¬λ₯Ό μΆκ°νμΈμ.
// β λμ μ: μμΈ μ²λ¦¬ μμ
const user = await UserModel.findById("A", userId); // 404 μλ¬ κ°λ₯
// β
μ’μ μ: μμΈ μ²λ¦¬
try {
const user = await UserModel.findById("A", userId);
} catch (error) {
if (error instanceof NotFoundException) {
// μ μ ν μ²λ¦¬
}
}
3. null κ°λ₯μ±
λ μ½λ μ‘΄μ¬ μ¬λΆκ° λΆνμ€νλ©΄ findOneμ μ¬μ©νμΈμ (μ§μ ꡬν νμ).
// findById: λ μ½λκ° λ°λμ μ‘΄μ¬ν΄μΌ ν¨
const user = await UserModel.findById("A", 1);
// findOne: λ μ½λκ° μμ μ μμ (μ§μ ꡬν νμ)
const user = await UserModel.findOne("A", { email: "[email protected]" });
if (user === null) {
// λ μ½λ μμ μ²λ¦¬
}
λ€μ λ¨κ³