Skip to content

Commit

Permalink
Refactor: migrate populate directory to TS
Browse files Browse the repository at this point in the history
  • Loading branch information
kmc7468 committed Feb 3, 2024
1 parent 7795c73 commit 8d58a79
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 105 deletions.
10 changes: 0 additions & 10 deletions src/modules/populates/chats.js

This file was deleted.

12 changes: 12 additions & 0 deletions src/modules/populates/chats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type User, type Chat } from "@/types/mongo";

/** @constant {{path: string, select: string}[]}
* 쿼리를 통해 얻은 Chat Document를 populate할 설정값을 정의합니다.
*/
export const chatPopulateOption = [
{ path: "authorId", select: "_id nickname profileImageUrl" },
];

export interface PopulatedChat extends Omit<Chat, "authorId"> {
authorId?: Pick<User, "_id" | "nickname" | "profileImageUrl">;
};
10 changes: 0 additions & 10 deletions src/modules/populates/reports.js

This file was deleted.

12 changes: 12 additions & 0 deletions src/modules/populates/reports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type User, type Report } from "@/types/mongo";

export const reportPopulateOption = [
{
path: "reportedId",
select: "_id id name nickname profileImageUrl",
},
];

export interface PopulatedReport extends Omit<Report, "reportedId"> {
reportedId: Pick<User, "_id" | "id" | "name" | "nickname" | "profileImageUrl">;
};
73 changes: 0 additions & 73 deletions src/modules/populates/rooms.js

This file was deleted.

93 changes: 93 additions & 0 deletions src/modules/populates/rooms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { type User, type SettlementStatus, type Participant, type Room, type Location } from "@/types/mongo";

/**
* 쿼리를 통해 얻은 Room Document를 populate할 설정값을 정의합니다.
* @constant {{path: string, select: string, populate?: {path: string, select: string}}[]}
*/
export const roomPopulateOption = [
{ path: "from", select: "_id koName enName" },
{ path: "to", select: "_id koName enName" },
{
path: "part",
select: "-_id user settlementStatus readAt",
populate: { path: "user", select: "_id id name nickname profileImageUrl" },
},
];

interface PopulatedParticipant extends Pick<Participant, "settlementStatus" | "readAt"> {
user: Pick<User, "_id" | "id" | "name" | "nickname" | "profileImageUrl">;
}

export interface PopulatedRoom extends Omit<Room, "from" | "to" | "part"> {
from: Pick<Location, "_id" | "koName" | "enName">;
to: Pick<Location, "_id" | "koName" | "enName">;
part?: PopulatedParticipant[];
}

export interface FormattedRoom extends Omit<PopulatedRoom, "part" | "settlementTotal"> {
part?: {
_id: string;
name: string;
nickname: string;
profileImageUrl: string;
isSettlement?: SettlementStatus;
readAt: Date;
}[];
settlementTotal?: number;
isOver?: boolean;
isDeparted: boolean;
};

/**
* Room Object가 주어졌을 때 room의 part array의 각 요소를 API 명세에서와 같이 {userId: String, ... , isSettlement: String}으로 가공합니다.
* 또한, 방이 현재 출발했는지 유무인 isDeparted 속성을 추가합니다.
* @param {PopulatedRoom} roomObject - 정산 정보를 가공할 room Object로, Mongoose Document가 아닌 순수 Javascript Object여야 합니다.
* @param {Object} options - 추가 파라미터로, 기본값은 {}입니다.
* @param {Boolean} options.includeSettlement - 반환 결과에 정산 정보를 포함할 지 여부로, 기본값은 true입니다.
* @param {Date} options.timestamp - 방의 출발 여부(isDeparted)를 판단하는 기준이 되는 시각입니다.
* @param {Boolean} options.isOver - 방의 완료 여부(isOver)로, 기본값은 false입니다. includeSettlement가 false인 경우 roomDocument의 isOver 속성은 undefined로 설정됩니다.
* @return {FormattedRoom} 정산 여부가 위와 같이 가공되고 isDeparted 속성이 추가된 Room Object가 반환됩니다.
*/
export const formatSettlement = (
roomObject: PopulatedRoom,
{ includeSettlement = true, isOver = false, timestamp = Date.now() } = {}
): FormattedRoom => {
return {
...roomObject,
part: roomObject.part?.map((participantSubDocument) => {
const { _id, name, nickname, profileImageUrl } =
participantSubDocument.user;
const { settlementStatus, readAt } = participantSubDocument;
return {
_id,
name,
nickname,
profileImageUrl,
isSettlement: includeSettlement ? settlementStatus : undefined,
readAt: readAt ?? roomObject.madeat,
};
}),
settlementTotal: includeSettlement ? roomObject.settlementTotal : undefined,
isOver: includeSettlement ? isOver : undefined,
isDeparted: new Date(roomObject.time) < new Date(timestamp),
};
}

/**
* roomPopulateOption을 사용해 populate된 Room Object와 사용자의 id(userId)가 주어졌을 때, 해당 사용자의 정산 상태를 반환합니다.
* @param {PopulatedRoom} roomObject - roomPopulateOption을 사용해 populate된 변환한 Room Object입니다.
* @param {String} userId - 방 완료 상태를 확인하려는 사용자의 id(user.id)입니다.
* @return {Boolean | undefined} 사용자의 해당 방에 대한 완료 여부(true | false)를 반환합니다. 사용자가 참여중인 방이 아닐 경우 undefined를 반환합니다.
**/
export const getIsOver = (roomObject: PopulatedRoom, userId: string) => {
// room document의 part subdoocument에서 사용자 id와 일치하는 정산 정보를 찾습니다.
const participantSubDocuments = roomObject.part?.filter((part) => {
return part.user.id === userId;
});

// 방에 참여중이지 않은 사용자의 경우, undefined을 반환합니다.
if (!participantSubDocuments || participantSubDocuments.length === 0) return undefined;

// 방에 참여중인 사용자의 경우, 정산 상태가 완료된 것인지("paid"거나 "sent"인지)를 반환합니다.
return ["paid", "sent"].includes(participantSubDocuments[0].settlementStatus);
};
24 changes: 12 additions & 12 deletions src/types/mongo.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Types } from "mongoose";
import { Document, Types } from "mongoose";

export interface User {
export interface User extends Document {
/** 사용자의 실명. */
name: string;
/** 사용자의 닉네임. */
Expand Down Expand Up @@ -39,7 +39,7 @@ export interface User {

export type SettlementStatus = "not-departed" | "paid" | "send-required" | "sent";

export interface Participant {
export interface Participant extends Document {
/** 방 참여자의 User ObjectID. */
user: Types.ObjectId;
/** 방 참여자의 정산 상태. */
Expand All @@ -48,14 +48,14 @@ export interface Participant {
readAt?: Date;
}

export interface DeviceToken {
export interface DeviceToken extends Document {
/** 디바이스 토큰 소유자의 User ObjectID. */
userId: Types.ObjectId;
/** 소유한 디바이스 토큰의 배열. */
deviceTokens: Types.Array<string>;
}

export interface NotificationOption {
export interface NotificationOption extends Document {
deviceToken: string;
/** 채팅 알림 수신 여부. */
chatting: boolean;
Expand All @@ -69,13 +69,13 @@ export interface NotificationOption {
advertisement: boolean;
}

export interface TopicSubscription {
export interface TopicSubscription extends Document {
deviceToken?: string;
topic?: string;
subscribedAt: Date;
}

export interface Room {
export interface Room extends Document {
/** 방의 이름. */
name: string;
/** 방의 출발지의 Location ObjectID. */
Expand All @@ -94,7 +94,7 @@ export interface Room {
maxPartLength: number;
}

export interface Location {
export interface Location extends Document {
enName: string;
koName: string;
priority: number;
Expand All @@ -116,7 +116,7 @@ export type ChatType =
| "departure"
| "arrival";

export interface Chat {
export interface Chat extends Document {
/** 메세지가 전송된 방의 Room ObjectID. */
roomId: Types.ObjectId;
/** 메세지의 종류. */
Expand All @@ -128,7 +128,7 @@ export interface Chat {
isValid: boolean;
}

export interface Report {
export interface Report extends Document {
/** 신고한 사용자의 ObjectID. */
creatorId: Types.ObjectId;
/** 신고받은 사용자의 ObjectID. */
Expand All @@ -143,14 +143,14 @@ export interface Report {
roomId?: Types.ObjectId;
}

export interface AdminIPWhitelist {
export interface AdminIPWhitelist extends Document {
ip: string;
description: string;
}

export type AdminLogAction = "create" | "read" | "update" | "delete";

export interface AdminLog {
export interface AdminLog extends Document {
/** 로그 발생자의 User ObjectID. */
user: Types.ObjectId;
/** 로그의 발생 시각. */
Expand Down

0 comments on commit 8d58a79

Please sign in to comment.