Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

폴더 목록 및 기본폴더 생성 #40

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/common/types/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ export type JwtPayload = {
export type ReqUserPayload = {
id: string;
};

export type FunctionType = (...args: any[]) => any;
10 changes: 10 additions & 0 deletions src/common/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
import { FunctionType } from '../types/type';

export * from './parser.util';
export * from './math.util';

export const pipe = (...functions: FunctionType[]) => {
return (initial: unknown) =>
functions.reduce((result, func) => {
return func(result);
}, initial);
};
9 changes: 9 additions & 0 deletions src/common/utils/math.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const sum = <T = number | object>(
_list: T[],
selector?: T extends object ? (item: T) => number : never,
): number => {
if (_list.length === 0) return 0;

const list = (selector ? _list.map(selector) : _list) as number[];
return list.reduce((sum, cur) => cur + sum, 0);
};
9 changes: 9 additions & 0 deletions src/domains/folder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { FolderType } from '@src/infrastructure/database/types/folder-type.enum';

export class FolderDomain {
userId: string;

name: string;

type: FolderType;
}
Comment on lines +3 to +9
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

도메인으로 따로 빼는 기준 궁금쓰

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

없앰 ㅎㅎ

1 change: 0 additions & 1 deletion src/infrastructure/database/schema/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ export * from './folder.schema';
export * from './keyword.schema';
export * from './post.schema';
export * from './AIClassification.schema';
export * from './postUserRead.schema';
4 changes: 4 additions & 0 deletions src/infrastructure/database/types/folder-type.enum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export enum FolderType {
CUSTOM = 'custom',
DEFAULT = 'default',

/** 실제 DB에 들어가지는 않고 클라이언트에 내려주기 위해 있는 값 타입 */
ALL = 'all',
FAVORITE = 'favorite',
}
Comment on lines 3 to 8
Copy link
Collaborator

@hye-on hye-on Jul 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그럼 DEFAULT 인 폴더는 "나중에 읽을 링크" 만 있는건강 궁금쓰

7 changes: 5 additions & 2 deletions src/modules/folders/dto/folder-with-count.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { FolderDomain } from '@src/domains/folder';
import { FolderDocument } from '@src/infrastructure';

export interface FolderWithCount extends FolderDocument {
postCount: number;
export interface FolderListServiceDto {
/** */
defaultFolders: any[];
customFolders: any[];
}
Comment on lines +4 to 8
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파일 이름은 안바뀌나욤?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

바꿈

4 changes: 2 additions & 2 deletions src/modules/folders/folders.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ export class FoldersController {
@FindAFolderListDocs
@Get()
async findAll(@GetUser() userId: string) {
const folders = await this.foldersService.findAll(userId);
return new FolderListResponse(folders);
const result = await this.foldersService.findAll(userId);
return new FolderListResponse(result);
}

@FindFolderDocs
Expand Down
4 changes: 3 additions & 1 deletion src/modules/folders/folders.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MongooseModule } from '@nestjs/mongoose';
import { Folder, FolderSchema, Post, PostSchema } from '@src/infrastructure';
import { FolderRepository } from './folders.repository';
import { PostsRepository } from '../posts/posts.repository';
import { PostsModule } from '../posts/posts.module';
import { PostsService } from '../posts/posts.service';

@Module({
Expand All @@ -13,8 +14,9 @@ import { PostsService } from '../posts/posts.service';
{ name: Post.name, schema: PostSchema },
{ name: Folder.name, schema: FolderSchema },
]),
PostsModule,
],
controllers: [FoldersController],
providers: [FoldersService, PostsService, FolderRepository, PostsRepository],
providers: [FoldersService, FolderRepository, PostsRepository],
})
export class FoldersModule {}
57 changes: 44 additions & 13 deletions src/modules/folders/folders.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Injectable } from '@nestjs/common';
import { CreateFolderDto, UpdateFolderDto } from './dto/mutate-folder.dto';
import { HydratedDocument, Schema as MongooseSchema } from 'mongoose';
import { FolderWithCount } from './dto/folder-with-count.dto';
import { Schema as MongooseSchema } from 'mongoose';
import { FolderRepository } from './folders.repository';
import { PostsRepository } from '../posts/posts.repository';
import { FolderType } from '@src/infrastructure/database/types/folder-type.enum';
import { Type } from 'class-transformer';
import { sum } from '@src/common';
import { FolderListServiceDto } from './dto/folder-with-count.dto';
import { Folder, FolderDocument } from '@src/infrastructure';

@Injectable()
export class FoldersService {
Expand All @@ -24,21 +25,51 @@ export class FoldersService {
await this.folderRepository.createMany(folders);
}

async findAll(userId: string): Promise<FolderWithCount[]> {
async findAll(userId: string): Promise<FolderListServiceDto> {
const folders = await this.folderRepository.findByUserId(userId);
const folderIds = folders.map((folder) => folder._id);

const posts = await this.postRepository.getPostCountByFolderIds(folderIds);
const groupedFolders =
await this.postRepository.getPostCountByFolderIds(folderIds);

const foldersWithCounts = folders.map((folder) => {
const post = posts.find((post) => post._id.equals(folder._id));
return {
...folder.toJSON(),
postCount: post?.count ?? 0,
} satisfies FolderWithCount;
});
const allPostCount = sum(groupedFolders, (folder) => folder.count);
const favoritePostCount =
await this.postRepository.findFavoritePostCount(userId);

const defaultFolder = folders.find(
(folder) => folder.type === FolderType.DEFAULT,
);
const customFolders = folders
.filter((folder) => folder.type === FolderType.CUSTOM)
.map((folder) => {
const post = groupedFolders.find((folder) =>
folder._id.equals(folder._id),
);
return {
...folder.toJSON(),
postCount: post?.count ?? 0,
};
});

const all = {
id: null,
name: '모든 링크',
type: FolderType.ALL,
userId: new MongooseSchema.Types.ObjectId(userId),
postCount: allPostCount,
Comment on lines +57 to +59
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MongooseSchema 별칭 쓴 이유 궁금쓰

};
const favorite = {
id: null,
name: '즐겨찾기',
type: FolderType.FAVORITE,
userId: new MongooseSchema.Types.ObjectId(userId),
postCount: favoritePostCount,
};

return foldersWithCounts;
const defaultFolders = [all, favorite, defaultFolder].filter(
(folder) => !!folder,
);
return { defaultFolders, customFolders };
}

async findOne(userId: string, folderId: string) {
Expand Down
17 changes: 8 additions & 9 deletions src/modules/folders/responses/folder-list.response.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ApiProperty } from '@nestjs/swagger';
import { FolderResponse } from './folder.response';
import { FolderWithCount } from '../dto/folder-with-count.dto';
import { FolderType } from '@src/infrastructure/database/types/folder-type.enum';
import { FolderListServiceDto } from '../dto/folder-with-count.dto';

export class FolderListResponse {
@ApiProperty({ isArray: true, type: FolderResponse })
Expand All @@ -10,13 +10,12 @@ export class FolderListResponse {
@ApiProperty({ isArray: true, type: FolderResponse })
customFolders: FolderResponse[];

constructor(data: FolderWithCount[]) {
this.defaultFolders = data
.filter((folder) => folder.type === FolderType.DEFAULT)
.map((folder) => new FolderResponse(folder));

this.customFolders = data
.filter((folder) => folder.type === FolderType.CUSTOM)
.map((folder) => new FolderResponse(folder));
constructor(data: FolderListServiceDto) {
this.defaultFolders = data.defaultFolders.map(
(folder) => new FolderResponse(folder),
);
this.customFolders = data.customFolders.map(
(folder) => new FolderResponse(folder),
);
}
}
2 changes: 1 addition & 1 deletion src/modules/folders/responses/folder-summary.response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class FolderSummaryResponse {
createdAt: Date;

constructor(data: FolderDocument) {
this.id = data._id.toString();
this.id = data._id ? data._id.toString() : data.id;
Comment on lines 18 to +19
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_id가 없으면 data.id 주는거 맞징
근데 FolderDocument에 id가 없는것 같은데(any 타입 넘겨서) 임시로 해둔건가?

this.name = data.name;
this.type = data.type;
this.createdAt = data.createdAt;
Expand Down
5 changes: 1 addition & 4 deletions src/modules/folders/responses/folder.response.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { ApiProperty } from '@nestjs/swagger';
import { FolderSummaryResponse } from './folder-summary.response';
import { Types } from 'mongoose';
import { FolderDocument } from '@src/infrastructure';
import { FolderWithCount } from '../dto/folder-with-count.dto';

export class FolderResponse extends FolderSummaryResponse {
@ApiProperty()
postCount: number;

constructor(data: FolderWithCount) {
constructor(data) {
super(data);

this.postCount = data.postCount;
Expand Down
2 changes: 1 addition & 1 deletion src/modules/folders/responses/post.response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class PostResponse {
isFavorite: boolean;

@ApiProperty()
createdAt: string;
createdAt: Date;

@ApiProperty({ type: Keyword, isArray: true })
keywords: Keyword[];
Expand Down
8 changes: 7 additions & 1 deletion src/modules/posts/posts.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ import { AwsLambdaService } from '@src/infrastructure/aws-lambda/aws-lambda.serv
AwsLambdaModule,
],
controllers: [PostsController],
providers: [PostsService, PostsRepository, FolderRepository, AwsLambdaService],
providers: [
PostsService,
PostsRepository,
FolderRepository,
AwsLambdaService,
],
exports: [PostsService],
})
export class PostsModule {}
15 changes: 12 additions & 3 deletions src/modules/posts/posts.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class PostsRepository {
}

async getPostCountByFolderIds(folderIds: Types.ObjectId[]) {
const posts = await this.postModel
const folders = await this.postModel
.aggregate<{ _id: Types.ObjectId; count: number }>([
{
$match: {
Expand All @@ -39,13 +39,13 @@ export class PostsRepository {
{
$group: {
_id: '$folderId',
count: { $sum: 1 },
postCount: { $sum: 1 },
},
},
])
.exec();

return posts;
return folders;
}

async getCountByFolderId(folderId: string) {
Expand All @@ -62,4 +62,13 @@ export class PostsRepository {

return folders;
}

async findFavoritePostCount(userId: string) {
const count = await this.postModel.countDocuments({
userId,
isFavorite: true,
});

return count;
}
}
10 changes: 7 additions & 3 deletions src/modules/users/users.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { MongooseModule } from '@nestjs/mongoose';
import { JwtStrategy } from './guards/strategy';
import { User, UserSchema } from '@src/infrastructure';
import { Folder, FolderSchema, User, UserSchema } from '@src/infrastructure';
import { UsersRepository } from './users.repository';
import { AuthModule } from '../auth/auth.module';
import { FolderRepository } from '../folders/folders.repository';

@Module({
imports: [
AuthModule,
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
MongooseModule.forFeature([
{ name: User.name, schema: UserSchema },
{ name: Folder.name, schema: FolderSchema },
]),
],
controllers: [UsersController],
providers: [UsersService, UsersRepository, JwtStrategy],
providers: [UsersService, UsersRepository, FolderRepository, JwtStrategy],
})
export class UsersModule {}
10 changes: 10 additions & 0 deletions src/modules/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import { CreateUserDto } from './dto';
import { JwtPayload } from 'src/common/types/type';
import { UsersRepository } from './users.repository';
import { AuthService } from '../auth/auth.service';
import { FolderRepository } from '../folders/folders.repository';
import { FolderType } from '@src/infrastructure/database/types/folder-type.enum';

@Injectable()
export class UsersService {
constructor(
private readonly userRepository: UsersRepository,
private readonly folderRepository: FolderRepository,
private readonly authService: AuthService,
) {}

Expand All @@ -20,6 +23,13 @@ export class UsersService {
};
// JWT Token 발급
const token = await this.authService.issueAccessToken(tokenPayload);

await this.folderRepository.create(
user._id.toString(),
'나중에 읽을 링크',
FolderType.DEFAULT,
);

return token;
}
}