๋ฉ”์ธ ์ฝ˜ํ…์ธ ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ
Subset์€ Model์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

Model ๋ฉ”์„œ๋“œ์™€ Subset

findById - ๋‹จ์ผ ๋ ˆ์ฝ”๋“œ ์กฐํšŒ

// Subset 1๊ฐœ
const user = await UserModel.findById(1, ["P"]);
// ํƒ€์ž…: UserSubsetMapping["P"]

// Subset ์—ฌ๋Ÿฌ ๊ฐœ (Union)
const user = await UserModel.findById(1, ["A", "P"]);
// ํƒ€์ž…: UserSubsetMapping["A"] | UserSubsetMapping["P"]

findOne - ์กฐ๊ฑด์œผ๋กœ ๋‹จ์ผ ๋ ˆ์ฝ”๋“œ

const user = await UserModel.findOne({
  where: [["email", "[email protected]"]],
  subsetKey: "P",
});
// ํƒ€์ž…: UserSubsetMapping["P"] | undefined

findMany - ์—ฌ๋Ÿฌ ๋ ˆ์ฝ”๋“œ ์กฐํšŒ

const users = await UserModel.findMany({
  listParams: {
    page: 1,
    pageSize: 20,
  },
  subsetKey: "L",
});
// ํƒ€์ž…: UserSubsetMapping["L"][]

getPuri๋กœ Subset ์ฟผ๋ฆฌ ์‹œ์ž‘

getPuri๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Subset ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค:
// Subset P์˜ ์ฟผ๋ฆฌ ์‹œ์ž‘
const query = UserModel.getPuri("r", ["P"]);

// ์ถ”๊ฐ€ ์กฐ๊ฑด ์ ์šฉ
const users = await query
  .where("users.role", "admin")
  .where("users.is_verified", true)
  .orderBy("users.created_at", "desc");

// ํƒ€์ž…: UserSubsetMapping["P"][]
getPuri("r", ["P"])๋Š” Subset P์— ์ •์˜๋œ JOIN๊ณผ SELECT๋ฅผ ์ž๋™์œผ๋กœ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Subset ์ฟผ๋ฆฌ ํ™•์žฅ

WHERE ์กฐ๊ฑด ์ถ”๊ฐ€

const admins = await UserModel.getPuri("r", ["L"])
  .where("users.role", "admin")
  .where("users.is_verified", true);

// Subset L์˜ ๊ธฐ๋ณธ ํ•„๋“œ + WHERE ์กฐ๊ฑด

ORDER BY ์ •๋ ฌ

const recentUsers = await UserModel.getPuri("r", ["L"])
  .orderBy("users.created_at", "desc")
  .limit(10);

๋ณตํ•ฉ ์กฐ๊ฑด

const activeEngineers = await UserModel.getPuri("r", ["P"])
  .where("users.role", "normal")
  .where("employee__department.name", "Engineering")
  .where("employee.salary", ">", "60000")
  .orderBy("employee.salary", "desc");

// Subset P๋Š” employee.department.name์„ ํฌํ•จํ•˜๋ฏ€๋กœ
// JOIN์ด ์ž๋™์œผ๋กœ ์„ค์ •๋จ

Subset ํƒ€์ž… ์•ˆ์ „์„ฑ

Subset ํƒ€์ž… ์•ˆ์ „์„ฑ

์ปดํŒŒ์ผ ํƒ€์ž„ ๊ฒ€์ฆ

// โœ… OK: Subset P๋Š” employee__department ํ…Œ์ด๋ธ” ํฌํ•จ
await UserModel.getPuri("r", ["P"])
  .where("employee__department.name", "Engineering");

// โŒ Type Error: Subset L์€ employee ํ…Œ์ด๋ธ” ๋ฏธํฌํ•จ
await UserModel.getPuri("r", ["L"])
  .where("employee__department.name", "Engineering");
//     ^^^^^^^^^^^^^^^^^^^^^^^^^ Property does not exist

์ž๋™ ํƒ€์ž… ์ถ”๋ก 

const user = await UserModel.findById(1, ["P"]);

// TypeScript๊ฐ€ ์ž๋™์œผ๋กœ ํƒ€์ž… ์ถ”๋ก 
user.id;        // number
user.username;  // string
user.employee;  // { salary: string; department: { name: string } } | null

// โŒ Compile Error
user.password;  // Property 'password' does not exist

์‹ค์ „ ์˜ˆ์ œ

์‚ฌ์šฉ์ž ๋ชฉ๋ก API

// Controller
class UserController {
  async list(req: TypedRequest<UserListParams>) {
    const { page, pageSize, role, search } = req.body;
    
    let query = UserModel.getPuri("r", ["L"]);
    
    // ์—ญํ•  ํ•„ํ„ฐ
    if (role) {
      query = query.where("users.role", role);
    }
    
    // ๊ฒ€์ƒ‰
    if (search) {
      query = query.where("users.username", "like", `%${search}%`);
    }
    
    const users = await query
      .orderBy("users.created_at", "desc")
      .limit(pageSize)
      .offset((page - 1) * pageSize);
    
    return users;
  }
}

ํ”„๋กœํ•„ ์กฐํšŒ API

async getProfile(userId: number) {
  const user = await UserModel.findById(userId, ["P"]);
  
  if (!user) {
    throw new NotFoundException("User not found");
  }
  
  return {
    id: user.id,
    username: user.username,
    email: user.email,
    bio: user.bio,
    department: user.employee?.department?.name,
    salary: user.employee?.salary,
  };
}

๋ณตํ•ฉ ๊ฒ€์ƒ‰ API

async searchUsers(params: {
  role?: UserRole;
  departmentName?: string;
  minSalary?: number;
}) {
  let query = UserModel.getPuri("r", ["P"]);
  
  if (params.role) {
    query = query.where("users.role", params.role);
  }
  
  if (params.departmentName) {
    query = query.where(
      "employee__department.name",
      "like",
      `%${params.departmentName}%`
    );
  }
  
  if (params.minSalary) {
    query = query.where("employee.salary", ">=", String(params.minSalary));
  }
  
  return await query.orderBy("users.username", "asc");
}

Subset ์กฐํ•ฉ

์—ฌ๋Ÿฌ Subset ์‚ฌ์šฉ (Union)

// ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ Subset ์‚ฌ์šฉ
async getUser(userId: number, detailed: boolean) {
  if (detailed) {
    return await UserModel.findById(userId, ["P"]);
    // ํƒ€์ž…: UserSubsetMapping["P"] | undefined
  } else {
    return await UserModel.findById(userId, ["SS"]);
    // ํƒ€์ž…: UserSubsetMapping["SS"] | undefined
  }
}

์กฐ๊ฑด๋ถ€ Subset ์„ ํƒ

async getUserData(userId: number, role: UserRole) {
  const subsets = role === "admin" ? ["A"] : ["P"];
  
  return await UserModel.findById(userId, subsets);
  // ํƒ€์ž…: UserSubsetMapping["A"] | UserSubsetMapping["P"] | undefined
}

์„ฑ๋Šฅ ์ตœ์ ํ™”

ํ•„์š”ํ•œ Subset๋งŒ ์‚ฌ์šฉ

// โŒ ๋‚˜์จ: ๋ชฉ๋ก์—์„œ Subset A ์‚ฌ์šฉ (๊ณผ๋„ํ•œ ๋ฐ์ดํ„ฐ)
const users = await UserModel.findMany({
  listParams: { page: 1, pageSize: 20 },
  subsetKey: "A",  // ๋ชจ๋“  ํ•„๋“œ ๋กœ๋”ฉ
});

// โœ… ์ข‹์Œ: ๋ชฉ๋ก์—๋Š” Subset L ์‚ฌ์šฉ
const users = await UserModel.findMany({
  listParams: { page: 1, pageSize: 20 },
  subsetKey: "L",  // ํ•„์š”ํ•œ ํ•„๋“œ๋งŒ
});

JOIN ์ตœ์†Œํ™”

// โŒ ๋‚˜์จ: ๋ถˆํ•„์š”ํ•œ JOIN (Subset P)
const userIds = await UserModel.getPuri("r", ["P"])
  .pluck("users.id");
// employee, department ํ…Œ์ด๋ธ”๋„ JOIN๋จ

// โœ… ์ข‹์Œ: JOIN ์—†๋Š” Subset (SS)
const userIds = await UserModel.getPuri("r", ["SS"])
  .pluck("users.id");
// users ํ…Œ์ด๋ธ”๋งŒ ์กฐํšŒ

Subset๊ณผ Raw Puri ๋น„๊ต

Subset ์‚ฌ์šฉ

// โœ… Subset - ํƒ€์ž… ์•ˆ์ „, ๊ฐ„๊ฒฐ
const users = await UserModel.getPuri("r", ["P"])
  .where("users.role", "admin");

// ํƒ€์ž…: UserSubsetMapping["P"][]
// JOIN ์ž๋™ ์„ค์ •
// SELECT ์ž๋™ ์„ค์ •

Raw Puri ์‚ฌ์šฉ

// โš ๏ธ Raw Puri - ์ˆ˜๋™ ์„ค์ •
const users = await UserModel.getPuri("r")
  .table("users")
  .leftJoin("employees", "users.id", "employees.user_id")
  .leftJoin("departments", "employees.department_id", "departments.id")
  .select({
    id: "users.id",
    username: "users.username",
    employee__salary: "employees.salary",
    employee__department__name: "departments.name",
  })
  .where("users.role", "admin");

// ํƒ€์ž…: { id: number; username: string; ... }[]
// JOIN ์ˆ˜๋™ ์„ค์ •
// SELECT ์ˆ˜๋™ ์„ค์ •
// Hydrate ์ˆ˜๋™ ์ ์šฉ ํ•„์š”
Subset์„ ์‚ฌ์šฉํ•˜์„ธ์š”!
  • ํƒ€์ž… ์•ˆ์ „์„ฑ ๋ณด์žฅ
  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ ํ–ฅ์ƒ
  • ์œ ์ง€๋ณด์ˆ˜ ํŽธ๋ฆฌ
  • ์ฟผ๋ฆฌ ์ผ๊ด€์„ฑ ์œ ์ง€

๋‹ค์Œ ๋‹จ๊ณ„