Skip to content

Commit

Permalink
[GWL-247] [Feat]: paginate 함수에 find (FindManyOptions) -> queryBuilder…
Browse files Browse the repository at this point in the history
…로 바꾸기 (#250)

* fix: paginate queryBuilder 사용

* fix: profile service 변경한 paginate 적용

* fix: post swagger 작성

* chore: format 적용

* chore: src 제거

---------

Co-authored-by: jeong-yong-shin <[email protected]>
  • Loading branch information
sjy982 and jeong-yong-shin authored Dec 6, 2023
1 parent d2c1ac5 commit 85d3b9a
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 25 deletions.
35 changes: 31 additions & 4 deletions BackEnd/src/common/common.service.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
import { Injectable } from '@nestjs/common';
import { FindManyOptions, Repository } from 'typeorm';
import { FindManyOptions, QueryBuilder, Repository } from 'typeorm';
import { BasePaginationDto } from './dto/base-pagination.dto';
import { ORM_OPERATION } from './const/orm-operation.const';
import { BaseModel } from './type/base-model.type';
import { JoinType, QueryOptions } from './type/query-options.type';

@Injectable()
export class CommonService {
async paginate<T extends BaseModel>(
paginationDto: BasePaginationDto,
repository: Repository<T>,
queryOptions: QueryOptions,
overrideFindOptions: FindManyOptions<T> = {},
) {
const findManyOptions: FindManyOptions<T> = {
...overrideFindOptions,
};
this.composeFindManyOptions(paginationDto, findManyOptions);
const results: Array<T> = await repository.find(findManyOptions);
const lastItemId: number = results.length > 0 ? results[results.length - 1].id : null;
const isLastCursor: boolean = results.length === paginationDto.take ? false : true;
const queryBuilder = this.makeQueryBuilder<T>(
repository,
queryOptions,
findManyOptions,
);
const results: Array<T> = await queryBuilder.getMany();
const lastItemId: number =
results.length > 0 ? results[results.length - 1].id : null;
const isLastCursor: boolean =
results.length === paginationDto.take ? false : true;
return {
items: results,
metaData: {
Expand Down Expand Up @@ -51,4 +60,22 @@ export class CommonService {
}
}
}

makeQueryBuilder<T>(
repository: Repository<T>,
queryOptions: QueryOptions,
findManyOptions: FindManyOptions<T> = {},
) {
let queryBilder = repository.createQueryBuilder(queryOptions.mainAlias);
queryBilder = queryBilder.setFindOptions(findManyOptions);
if (queryOptions.join) {
queryOptions.join.forEach((value: JoinType) => {
queryBilder = queryBilder.leftJoin(value.joinColumn, value.joinAlias);
});
}
if (queryOptions.select) {
queryBilder = queryBilder.select(queryOptions.select);
}
return queryBilder;
}
}
10 changes: 10 additions & 0 deletions BackEnd/src/common/type/query-options.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface JoinType {
joinColumn: string;
joinAlias: string;
}

export interface QueryOptions {
mainAlias: string;
join?: JoinType[];
select?: string[];
}
27 changes: 24 additions & 3 deletions BackEnd/src/posts/dto/get-posts-response.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import { ApiProperty, PickType } from '@nestjs/swagger';
import { SuccessResDto } from '../../common/dto/SuccessRes.dto';
import { Post } from '../entities/posts.entity';
import { Record } from '../../records/entities/records.entity';
import { Profile } from '../../profiles/entities/profiles.entity';

class PostRecordDto extends PickType(Record, [
'id',
'workoutTime',
'distance',
'calorie',
'avgHeartRate',
'minHeartRate',
'maxHeartRate',
]) {}

class PostProfileDto extends PickType(Profile, ['nickname']) {}

export class PostDto extends PickType(Post, [
'id',
Expand All @@ -11,18 +25,25 @@ export class PostDto extends PickType(Post, [
'updatedAt',
'deletedAt',
'postUrl',
]) {}
]) {
@ApiProperty({ type: () => PostRecordDto })
record: PostRecordDto;

@ApiProperty({ type: () => PostProfileDto })
profile: PostProfileDto;
}

export class MetaDataDto {
@ApiProperty({
example: 5,
description: 'lastItem의 id를 의미합니다. (where__is__less_then, where__is__more_then의 value 값으로 그대로 넣으시면 됩니다.) 아이템이 없으면 null이 들어옵니다.',
description:
'lastItem의 id를 의미합니다. (where__is__less_then, where__is__more_then의 value 값으로 그대로 넣으시면 됩니다.) 아이템이 없으면 null이 들어옵니다.',
})
lastItemId: number;

@ApiProperty({
example: false,
description: '마지막 커서가 아니라면 false, 마지막 커서라면 true'
description: '마지막 커서가 아니라면 false, 마지막 커서라면 true',
})
isLastCursor: boolean;

Expand Down
4 changes: 2 additions & 2 deletions BackEnd/src/posts/posts.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
Get,
Param,
ParseIntPipe,
Patch,
Post,
Put,
Query,
Expand All @@ -24,7 +23,7 @@ import { Profile } from '../profiles/entities/profiles.entity';
import { ProfileDeco } from '../profiles/decorator/profile.decorator';
import { PaginatePostDto } from './dto/paginate-post.dto';
import { GetPostsResponseDto } from './dto/get-posts-response.dto';
import { GetPostResponseDto } from './dto/get-post-response.dto';
import { GetPostResponseDto } from './dto/get-create-update-post-response.dto';
import { UpdatePostDto } from './dto/update-post.dto';
import { DeletePostResponseDto } from './dto/delete-post-response.dto';

Expand All @@ -36,6 +35,7 @@ export class PostsController {
@UseGuards(AccessTokenGuard)
@Post()
@ApiOperation({ summary: '게시글 생성' })
@ApiCreatedResponse({ type: GetPostResponseDto })
@ApiBody({ type: CreatePostDto })
async createPost(
@Body() body: CreatePostDto,
Expand Down
28 changes: 19 additions & 9 deletions BackEnd/src/posts/posts.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Post } from './entities/posts.entity';
import { FindManyOptions, Repository } from 'typeorm';
import { Repository } from 'typeorm';
import { CreatePostDto } from './dto/create-post.dto';
import { RecordsService } from '../records/records.service';
import { Profile } from '../profiles/entities/profiles.entity';
Expand All @@ -12,6 +12,7 @@ import {
import { PaginatePostDto } from './dto/paginate-post.dto';
import { CommonService } from '../common/common.service';
import { UpdatePostDto } from './dto/update-post.dto';
import { getCreateUpdateQueryOptions } from './queryOptions/get-create-update.queryOptions';

@Injectable()
export class PostsService {
Expand All @@ -27,42 +28,51 @@ export class PostsService {
if (record.isPosted) {
throw new ExistPostException();
}
await this.recordService.updateIsPostedTrue(record);
return await this.postsRepository.save({
this.recordService.updateIsPostedTrue(record);
const post = await this.postsRepository.save({
publicId: profile.publicId,
content: postInfo.content,
postUrl: postInfo.postUrl,
record,
profile,
});
return await this.findOneById(post.id);
}

async paginatePosts(query: PaginatePostDto) {
return await this.commonService.paginate<Post>(query, this.postsRepository);
return await this.commonService.paginate<Post>(
query,
this.postsRepository,
getCreateUpdateQueryOptions,
);
}

async findOneById(id: number) {
const post = await this.postsRepository.findOneBy({ id });
const queryBuilder = this.commonService.makeQueryBuilder(
this.postsRepository,
getCreateUpdateQueryOptions,
{ where: { id } },
);
const post = await queryBuilder.getOne();
if (!post) {
throw new NotFoundPostException();
}
return post;
}

async paginateUserPosts(publicId: string, query: PaginatePostDto) {
const findManyOptions: FindManyOptions<Post> = {};
findManyOptions.where = { publicId };
return await this.commonService.paginate<Post>(
query,
this.postsRepository,
findManyOptions,
getCreateUpdateQueryOptions,
{ where: { publicId } },
);
}

async updatePost(id: number, updatePostInfo: UpdatePostDto) {
await this.findOneById(id);
await this.postsRepository.update(id, updatePostInfo);
return await this.postsRepository.findOneBy({ id });
return await this.findOneById(id);
}

async deletePost(id: number) {
Expand Down
26 changes: 26 additions & 0 deletions BackEnd/src/posts/queryOptions/get-create-update.queryOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { QueryOptions } from '../../common/type/query-options.type';

export const getCreateUpdateQueryOptions: QueryOptions = {
mainAlias: 'post',
join: [
{
joinColumn: 'post.record',
joinAlias: 'record',
},
{
joinColumn: 'post.profile',
joinAlias: 'profile',
},
],
select: [
'post',
'record.id',
'record.workoutTime',
'record.distance',
'record.calorie',
'record.avgHeartRate',
'record.minHeartRate',
'record.maxHeartRate',
'profile.nickname',
],
};
1 change: 0 additions & 1 deletion BackEnd/src/profiles/profiles.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
ApiBody,
ApiCreatedResponse,
ApiOperation,
ApiResponse,
ApiTags,
} from '@nestjs/swagger';
import { AccessTokenGuard } from '../auth/guard/bearerToken.guard';
Expand Down
13 changes: 7 additions & 6 deletions BackEnd/src/profiles/profiles.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Injectable } from '@nestjs/common';
import { FindManyOptions, Repository } from 'typeorm';
import { Repository } from 'typeorm';
import { Profile } from './entities/profiles.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { UpdateProfileDto } from './dto/update-profile.dto';
import { Post } from '../posts/entities/posts.entity';
import { PaginateProfilePostDto } from './dto/paginate-profile-post.dto';
import { CommonService } from '../common/common.service';
import { NicknameDuplicateException } from '../auth/exceptions/auth.exception';
import { getProfilePostsQueryOptions } from './queryOptions/get-profilePosts-queryOptions';

@Injectable()
export class ProfilesService {
Expand Down Expand Up @@ -47,14 +48,14 @@ export class ProfilesService {
}

async getProfilePosts(publicId: string, query: PaginateProfilePostDto) {
const findManyOptions: FindManyOptions<Post> = {
where: { publicId },
select: ['id', 'postUrl'],
};
return await this.commonService.paginate<Post>(
query,
this.postsRepository,
findManyOptions,
getProfilePostsQueryOptions,
{
where: { publicId },
select: ['id', 'postUrl'],
},
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { QueryOptions } from '../../common/type/query-options.type';

export const getProfilePostsQueryOptions: QueryOptions = {
mainAlias: 'profile',
};

0 comments on commit 85d3b9a

Please sign in to comment.