From fd6cb4166e32bd4def5287ce6d589075c7727706 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 22:09:51 +0900 Subject: [PATCH 01/21] =?UTF-8?q?Feat:=20=EA=B9=83=ED=97=88=EB=B8=8C=20?= =?UTF-8?q?=EB=9E=AD=ED=81=AC=EB=A5=BC=20=EC=BF=BC=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/repository/github.repository.ts | 34 +++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/stat/repository/github.repository.ts b/src/stat/repository/github.repository.ts index ed44bcd..dd4ba6c 100644 --- a/src/stat/repository/github.repository.ts +++ b/src/stat/repository/github.repository.ts @@ -3,7 +3,7 @@ import { Inject, Injectable, Scope } from '@nestjs/common'; import { Github } from '../../Entity/github'; import { DataSource, Repository } from 'typeorm'; import { REQUEST } from '@nestjs/core'; -import { RankListOptionDto } from '../dto/rank-list-option.dto'; +import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { Algorithm } from '../../Entity/algorithm'; import { User } from '../../Entity/user'; import { PointFindDto } from '../dto/rank-find.dto'; @@ -73,4 +73,36 @@ export class GithubRepository extends BaseRepository { return `u.id > 0`; } } + + async findGithubWithRank( + options: RankListOptionDto, + ): Promise<[RankListDto]> { + const queryBuilder = this.repository + .createQueryBuilder() + .select(['b.rank', 'b.user_id', 'b.point', 'b.nickname']) + .distinct(true) + .from((sub) => { + return sub + .select('RANK() OVER (ORDER BY a.point DESC)', 'rank') + .addSelect('a.user_id', 'user_id') + .addSelect('a.point', 'point') + .addSelect('u.nickname', 'nickname') + .from(Github, 'a') + .innerJoin(User, 'u', 'a.user_id = u.user_id') + .where(this.createClassificationOption(options)); + }, 'b') + .where(this.createCursorOption(options)) + .orderBy('point', 'DESC') + .addOrderBy('user_id') + .limit(3); + return await (>queryBuilder.getRawMany()); + } + + createCursorOption(options: RankListOptionDto) { + if (!options.cursorPoint && !options.cursorUserId) { + return 'b.point > -1'; + } else { + return `b.point < ${options.cursorPoint} or b.point = ${options.cursorPoint} AND b.user_id > '${options.cursorUserId}'`; + } + } } From 45ca7da1f2356fb37592635da352911236851626 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 22:11:19 +0900 Subject: [PATCH 02/21] =?UTF-8?q?Feat:=20getGithubRank=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/service/github.service.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/stat/service/github.service.ts b/src/stat/service/github.service.ts index 0e485f2..d72988e 100644 --- a/src/stat/service/github.service.ts +++ b/src/stat/service/github.service.ts @@ -160,4 +160,13 @@ export class GithubService { // github.githubId = userResource.id; // await this.githubRepository.save(github); // } + async getGithubRank(options: RankListOptionDto) { + if ( + (options.cursorPoint && !options.cursorUserId) || + (!options.cursorPoint && options.cursorUserId) + ) { + throw new BadRequestException('Cursor Element Must Be Two'); + } + return await this.githubRepository.findGithubWithRank(options); + } } From e84b54e0d31d3fb5feaf3c0bb441c28a19d2394d Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 22:33:28 +0900 Subject: [PATCH 03/21] =?UTF-8?q?Feat:=20=EA=B9=83=ED=97=88=EB=B8=8C=20?= =?UTF-8?q?=EB=9E=AD=ED=81=AC=EB=A5=BC=20=EC=A1=B0=ED=9A=8C=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/rank.controller.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/stat/rank.controller.ts b/src/stat/rank.controller.ts index b477348..32092cd 100644 --- a/src/stat/rank.controller.ts +++ b/src/stat/rank.controller.ts @@ -52,6 +52,31 @@ export class RankController { return await this.algorithmService.getAlgorithms(options); } + @Get('github') + @ApiTags('rank') + @ApiOperation({ + summary: '깃허브 전체 랭킹 API', + description: + '깃허브 역량의 랭킹리스트를 반환한다. 페이지네이션이 가능하고 학과 별로 필터링 가능하다. (학번 필터링은 아직 미구현) 커서 사용시 cursorPoint, cursorUserId 두개를 동시에 넣어야한다. 각각 마지막으로 받은 유저의 점수와 유저 아이디이다.', + }) + @ApiBearerAuth('accessToken') + @ApiOkResponse({ + description: '깃허브 랭킹 반환', + type: [RankListDto], + }) + @ApiUnauthorizedResponse({ + description: 'jwt 관련 문제 (인증 시간이 만료됨, jwt를 보내지 않음)', + }) + @ApiForbiddenResponse({ + description: '허용되지 않은 자원에 접근한 경우. 즉, 권한이 없는 경우', + }) + @ApiInternalServerErrorResponse({ + description: '서버 오류', + }) + async findGithubRank(@Query() options: RankListOptionDto) { + return await this.githubService.getGithubRank(options); + } + @Get('/users/:id') @ApiTags('rank') @ApiOperation({ From c36137562698113d71e4326a596409c838fd2362 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 22:45:03 +0900 Subject: [PATCH 04/21] =?UTF-8?q?Feat:=20=ED=95=99=EC=A0=90=20=EB=9E=AD?= =?UTF-8?q?=ED=81=AC=EB=A5=BC=20=EC=BF=BC=EB=A6=AC=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/repository/grade.repository.ts | 34 ++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/stat/repository/grade.repository.ts b/src/stat/repository/grade.repository.ts index d7cd156..4ffd322 100644 --- a/src/stat/repository/grade.repository.ts +++ b/src/stat/repository/grade.repository.ts @@ -4,7 +4,7 @@ import { DataSource, Repository } from 'typeorm'; import { Github } from '../../Entity/github'; import { REQUEST } from '@nestjs/core'; import { Grade } from '../../Entity/grade'; -import { RankListOptionDto } from '../dto/rank-list-option.dto'; +import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { User } from '../../Entity/user'; import { PointFindDto } from '../dto/rank-find.dto'; @@ -61,6 +61,38 @@ export class GradeRepository extends BaseRepository { return await queryBuilder.getRawOne(); } + async findGradeWithRank( + options: RankListOptionDto, + ): Promise<[RankListDto]> { + const queryBuilder = this.repository + .createQueryBuilder() + .select(['b.rank', 'b.user_id', 'b.point', 'b.nickname']) + .distinct(true) + .from((sub) => { + return sub + .select('RANK() OVER (ORDER BY a.point DESC)', 'rank') + .addSelect('a.user_id', 'user_id') + .addSelect('a.point', 'point') + .addSelect('u.nickname', 'nickname') + .from(Grade, 'a') + .innerJoin(User, 'u', 'a.user_id = u.user_id') + .where(this.createClassificationOption(options)); + }, 'b') + .where(this.createCursorOption(options)) + .orderBy('point', 'DESC') + .addOrderBy('user_id') + .limit(3); + return await (>queryBuilder.getRawMany()); + } + + createCursorOption(options: RankListOptionDto) { + if (!options.cursorPoint && !options.cursorUserId) { + return 'b.point > -1'; + } else { + return `b.point < ${options.cursorPoint} or b.point = ${options.cursorPoint} AND b.user_id > '${options.cursorUserId}'`; + } + } + createClassificationOption(options: PointFindDto) { if (options.major != null) { return `u.major like '${options.major}'`; From 116d6165745b93f432ae7fba69cab91547220e6f Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 22:47:19 +0900 Subject: [PATCH 05/21] =?UTF-8?q?Feat:=20getGradeRank=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/service/grade.service.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/stat/service/grade.service.ts b/src/stat/service/grade.service.ts index c680eb1..661edaa 100644 --- a/src/stat/service/grade.service.ts +++ b/src/stat/service/grade.service.ts @@ -5,7 +5,7 @@ import { } from '@nestjs/common'; import { GradeRepository } from '../repository/grade.repository'; import { Grade } from '../../Entity/grade'; -import { RankListOptionDto } from '../dto/rank-list-option.dto'; +import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { PointFindDto } from '../dto/rank-find.dto'; @Injectable() @@ -65,4 +65,14 @@ export class GradeService { options, ); } + + async getGradeRank(options: RankListOptionDto): Promise<[RankListDto]> { + if ( + (options.cursorPoint && !options.cursorUserId) || + (!options.cursorPoint && options.cursorUserId) + ) { + throw new BadRequestException('Cursor Element Must Be Two'); + } + return await this.gradeRepository.findGradeWithRank(options); + } } From d90ecfed7e30d701bd7c6d86224c41b12b25b034 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 22:49:01 +0900 Subject: [PATCH 06/21] =?UTF-8?q?Feat:=20=20=ED=95=99=EC=A0=90=20=EB=9E=AD?= =?UTF-8?q?=ED=81=AC=EB=A5=BC=20=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/rank.controller.ts | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/stat/rank.controller.ts b/src/stat/rank.controller.ts index 32092cd..d3d8c0c 100644 --- a/src/stat/rank.controller.ts +++ b/src/stat/rank.controller.ts @@ -77,6 +77,56 @@ export class RankController { return await this.githubService.getGithubRank(options); } + @Get('grade') + @ApiTags('rank') + @ApiOperation({ + summary: '학점 전체 랭킹 API', + description: + '학점 역량의 랭킹리스트를 반환한다. 페이지네이션이 가능하고 학과 별로 필터링 가능하다. (학번 필터링은 아직 미구현) 커서 사용시 cursorPoint, cursorUserId 두개를 동시에 넣어야한다. 각각 마지막으로 받은 유저의 점수와 유저 아이디이다.', + }) + @ApiBearerAuth('accessToken') + @ApiOkResponse({ + description: '학점 랭킹 반환', + type: [RankListDto], + }) + @ApiUnauthorizedResponse({ + description: 'jwt 관련 문제 (인증 시간이 만료됨, jwt를 보내지 않음)', + }) + @ApiForbiddenResponse({ + description: '허용되지 않은 자원에 접근한 경우. 즉, 권한이 없는 경우', + }) + @ApiInternalServerErrorResponse({ + description: '서버 오류', + }) + async findGradeRank(@Query() options: RankListOptionDto) { + return await this.gradeService.getGradeRank(options); + } + + @Get('total') + @ApiTags('rank') + @ApiOperation({ + summary: '종 전체 랭킹 API', + description: + '학점 역량의 랭킹리스트를 반환한다. 페이지네이션이 가능하고 학과 별로 필터링 가능하다. (학번 필터링은 아직 미구현) 커서 사용시 cursorPoint, cursorUserId 두개를 동시에 넣어야한다. 각각 마지막으로 받은 유저의 점수와 유저 아이디이다.', + }) + @ApiBearerAuth('accessToken') + @ApiOkResponse({ + description: '종합 랭킹 반환', + type: [RankListDto], + }) + @ApiUnauthorizedResponse({ + description: 'jwt 관련 문제 (인증 시간이 만료됨, jwt를 보내지 않음)', + }) + @ApiForbiddenResponse({ + description: '허용되지 않은 자원에 접근한 경우. 즉, 권한이 없는 경우', + }) + @ApiInternalServerErrorResponse({ + description: '서버 오류', + }) + async findTotalRank(@Query() options: RankListOptionDto) { + return await this.totalService.getTotalRank(options); + } + @Get('/users/:id') @ApiTags('rank') @ApiOperation({ From efcad5f81f1124126cbb108772274e75d683b8a2 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 22:55:42 +0900 Subject: [PATCH 07/21] =?UTF-8?q?Feat:=20=EC=A2=85=ED=95=A9=20=EB=9E=AD?= =?UTF-8?q?=ED=81=AC=EB=A5=BC=20=EC=BF=BC=EB=A6=AC=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/repository/total.repository.ts | 35 ++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/stat/repository/total.repository.ts b/src/stat/repository/total.repository.ts index fd609a7..322ff6c 100644 --- a/src/stat/repository/total.repository.ts +++ b/src/stat/repository/total.repository.ts @@ -4,10 +4,11 @@ import { Grade } from '../../Entity/grade'; import { Inject } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { TotalPoint } from '../../Entity/totalPoint'; -import { RankListOptionDto } from '../dto/rank-list-option.dto'; +import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { Algorithm } from '../../Entity/algorithm'; import { User } from '../../Entity/user'; import { PointFindDto } from '../dto/rank-find.dto'; +import { Github } from '../../Entity/github'; export class TotalRepository extends BaseRepository { private repository: Repository; @@ -59,4 +60,36 @@ export class TotalRepository extends BaseRepository { return `u.id > 0`; } } + + async findTotalWithRank( + options: RankListOptionDto, + ): Promise<[RankListDto]> { + const queryBuilder = this.repository + .createQueryBuilder() + .select(['b.rank', 'b.user_id', 'b.point', 'b.nickname']) + .distinct(true) + .from((sub) => { + return sub + .select('RANK() OVER (ORDER BY a.point DESC)', 'rank') + .addSelect('a.user_id', 'user_id') + .addSelect('a.point', 'point') + .addSelect('u.nickname', 'nickname') + .from(TotalPoint, 'a') + .innerJoin(User, 'u', 'a.user_id = u.user_id') + .where(this.createClassificationOption(options)); + }, 'b') + .where(this.createCursorOption(options)) + .orderBy('point', 'DESC') + .addOrderBy('user_id') + .limit(3); + return await (>queryBuilder.getRawMany()); + } + + createCursorOption(options: RankListOptionDto) { + if (!options.cursorPoint && !options.cursorUserId) { + return 'b.point > -1'; + } else { + return `b.point < ${options.cursorPoint} or b.point = ${options.cursorPoint} AND b.user_id > '${options.cursorUserId}'`; + } + } } From 946a5a4cc0325d44c5848120ebd0c4a88a054448 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 22:56:13 +0900 Subject: [PATCH 08/21] =?UTF-8?q?Feat:=20getTotalRank=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/service/total.service.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/stat/service/total.service.ts b/src/stat/service/total.service.ts index 7e78597..5354441 100644 --- a/src/stat/service/total.service.ts +++ b/src/stat/service/total.service.ts @@ -7,7 +7,7 @@ import { GradeService } from './grade.service'; import { Github } from '../../Entity/github'; import { Grade } from '../../Entity/grade'; import { Algorithm } from '../../Entity/algorithm'; -import { RankListOptionDto } from '../dto/rank-list-option.dto'; +import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { PointFindDto } from '../dto/rank-find.dto'; @Injectable() @@ -30,6 +30,17 @@ export class TotalService { grade: grade ? grade.grade : null, }; } + + async getTotalRank(options: RankListOptionDto): Promise<[RankListDto]> { + if ( + (options.cursorPoint && !options.cursorUserId) || + (!options.cursorPoint && options.cursorUserId) + ) { + throw new BadRequestException('Cursor Element Must Be Two'); + } + return await this.totalRepository.findTotalWithRank(options); + } + async createTotalPoint(userId: string) { const isExist = await this.totalRepository.findOneById(userId); From b8b6fc5720bf4c229ebc12b9b4a924e7b86e3488 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 22:57:07 +0900 Subject: [PATCH 09/21] =?UTF-8?q?Feat:=20=20=EC=A2=85=ED=95=A9=20=EB=9E=AD?= =?UTF-8?q?=ED=81=AC=EB=A5=BC=20=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/rank.controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stat/rank.controller.ts b/src/stat/rank.controller.ts index d3d8c0c..128fe6d 100644 --- a/src/stat/rank.controller.ts +++ b/src/stat/rank.controller.ts @@ -86,7 +86,7 @@ export class RankController { }) @ApiBearerAuth('accessToken') @ApiOkResponse({ - description: '학점 랭킹 반환', + description: '깃허브 랭킹 반환', type: [RankListDto], }) @ApiUnauthorizedResponse({ @@ -105,7 +105,7 @@ export class RankController { @Get('total') @ApiTags('rank') @ApiOperation({ - summary: '종 전체 랭킹 API', + summary: '종합 전체 랭킹 API', description: '학점 역량의 랭킹리스트를 반환한다. 페이지네이션이 가능하고 학과 별로 필터링 가능하다. (학번 필터링은 아직 미구현) 커서 사용시 cursorPoint, cursorUserId 두개를 동시에 넣어야한다. 각각 마지막으로 받은 유저의 점수와 유저 아이디이다.', }) From 2a80ea14aa5f036c251c351f91ee7d50614fde80 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 23:09:31 +0900 Subject: [PATCH 10/21] =?UTF-8?q?Test:=20getAlgorithms=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/service/algorithm.service.spec.ts | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/stat/service/algorithm.service.spec.ts b/src/stat/service/algorithm.service.spec.ts index 5394688..5f40182 100644 --- a/src/stat/service/algorithm.service.spec.ts +++ b/src/stat/service/algorithm.service.spec.ts @@ -3,12 +3,14 @@ import { AlgorithmService } from './algorithm.service'; import axios from 'axios'; import { AlgorithmRepository } from '../repository/algorithm.repository'; import { Algorithm } from '../../Entity/algorithm'; +import { RankListOptionDto } from '../dto/rank-list-option.dto'; const mockAlgorithmRepository = { save: jest.fn(), findOneById: jest.fn(), update: jest.fn(), delete: jest.fn(), + findAlgorithmWithRank: jest.fn(), }; jest.mock('axios'); @@ -222,4 +224,25 @@ describe('AlgorithmService', () => { ); }); }); + + describe('getAlgorithms', function () { + it('cursor 를 하나만 보내면 오류를 던진다.', function () { + const options1: RankListOptionDto = { + cursorUserId: null, + major: null, + cursorPoint: 12, + }; + const options2: RankListOptionDto = { + cursorUserId: 'qwe', + major: null, + cursorPoint: null, + }; + expect(service.getAlgorithms(options1)).rejects.toThrow( + 'Cursor Element Must Be Two', + ); + expect(service.getAlgorithms(options2)).rejects.toThrow( + 'Cursor Element Must Be Two', + ); + }); + }); }); From 2d481388436351395f8d0a1d5c8c4bb4b3733257 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 23:31:16 +0900 Subject: [PATCH 11/21] =?UTF-8?q?Refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20import=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Entity/user.ts | 1 - src/app.module.ts | 2 -- src/stat/repository/algorithm.repository.ts | 1 - src/stat/repository/github.repository.ts | 3 +-- src/stat/repository/grade.repository.ts | 1 - src/stat/repository/total.repository.ts | 2 -- src/stat/service/github.service.ts | 1 - 7 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Entity/user.ts b/src/Entity/user.ts index ea6e4bb..946b90a 100644 --- a/src/Entity/user.ts +++ b/src/Entity/user.ts @@ -1,7 +1,6 @@ import { Column, CreateDateColumn, - DeleteDateColumn, Entity, OneToOne, PrimaryGeneratedColumn, diff --git a/src/app.module.ts b/src/app.module.ts index ae53ce8..39f3272 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -11,8 +11,6 @@ import * as process from 'process'; import { HttpLoggerInterceptor } from './utils/httpLoggerInterceptor'; import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core'; import { HttpExceptionFilter } from './utils/httpExceptionFilter'; -import { WinstonModule } from 'nest-winston'; -import { transports } from 'winston'; @Module({ imports: [ diff --git a/src/stat/repository/algorithm.repository.ts b/src/stat/repository/algorithm.repository.ts index 5f0eee7..d404976 100644 --- a/src/stat/repository/algorithm.repository.ts +++ b/src/stat/repository/algorithm.repository.ts @@ -5,7 +5,6 @@ import { REQUEST } from '@nestjs/core'; import { Algorithm } from '../../Entity/algorithm'; import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { User } from '../../Entity/user'; -import { RankController } from '../rank.controller'; import { PointFindDto } from '../dto/rank-find.dto'; @Injectable({ scope: Scope.REQUEST }) diff --git a/src/stat/repository/github.repository.ts b/src/stat/repository/github.repository.ts index dd4ba6c..1b071b1 100644 --- a/src/stat/repository/github.repository.ts +++ b/src/stat/repository/github.repository.ts @@ -1,10 +1,9 @@ import { BaseRepository } from '../../utils/base.repository'; -import { Inject, Injectable, Scope } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { Github } from '../../Entity/github'; import { DataSource, Repository } from 'typeorm'; import { REQUEST } from '@nestjs/core'; import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; -import { Algorithm } from '../../Entity/algorithm'; import { User } from '../../Entity/user'; import { PointFindDto } from '../dto/rank-find.dto'; diff --git a/src/stat/repository/grade.repository.ts b/src/stat/repository/grade.repository.ts index 4ffd322..4fd3432 100644 --- a/src/stat/repository/grade.repository.ts +++ b/src/stat/repository/grade.repository.ts @@ -1,7 +1,6 @@ import { BaseRepository } from '../../utils/base.repository'; import { Inject, Injectable } from '@nestjs/common'; import { DataSource, Repository } from 'typeorm'; -import { Github } from '../../Entity/github'; import { REQUEST } from '@nestjs/core'; import { Grade } from '../../Entity/grade'; import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; diff --git a/src/stat/repository/total.repository.ts b/src/stat/repository/total.repository.ts index 322ff6c..dd24c67 100644 --- a/src/stat/repository/total.repository.ts +++ b/src/stat/repository/total.repository.ts @@ -1,6 +1,5 @@ import { BaseRepository } from '../../utils/base.repository'; import { DataSource, Repository } from 'typeorm'; -import { Grade } from '../../Entity/grade'; import { Inject } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { TotalPoint } from '../../Entity/totalPoint'; @@ -8,7 +7,6 @@ import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { Algorithm } from '../../Entity/algorithm'; import { User } from '../../Entity/user'; import { PointFindDto } from '../dto/rank-find.dto'; -import { Github } from '../../Entity/github'; export class TotalRepository extends BaseRepository { private repository: Repository; diff --git a/src/stat/service/github.service.ts b/src/stat/service/github.service.ts index d72988e..9976df4 100644 --- a/src/stat/service/github.service.ts +++ b/src/stat/service/github.service.ts @@ -3,7 +3,6 @@ import { Injectable, InternalServerErrorException, Logger, - NotFoundException, } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { GithubRepository } from '../repository/github.repository'; From b634555145b2c9f45c86bce96893205de768683b Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 23:41:08 +0900 Subject: [PATCH 12/21] =?UTF-8?q?Feat:=20stat=EC=9D=84=20=EB=8B=A4?= =?UTF-8?q?=EB=A3=A8=EB=8A=94=20repository=EB=93=A4=EC=9D=B4=20=EA=B3=B5?= =?UTF-8?q?=EC=9C=A0=ED=95=A0=20StatRepository=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/stat.repository.ts | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/utils/stat.repository.ts diff --git a/src/utils/stat.repository.ts b/src/utils/stat.repository.ts new file mode 100644 index 0000000..3116cc8 --- /dev/null +++ b/src/utils/stat.repository.ts @@ -0,0 +1,59 @@ +import { BaseRepository } from './base.repository'; +import { DataSource, Repository } from 'typeorm'; +import { Algorithm } from '../Entity/algorithm'; +import { Inject } from '@nestjs/common'; +import { REQUEST } from '@nestjs/core'; +import { + RankListDto, + RankListOptionDto, +} from '../stat/dto/rank-list-option.dto'; +import { User } from '../Entity/user'; +import { PointFindDto } from '../stat/dto/rank-find.dto'; + +export class StatRepository extends BaseRepository { + protected repository: Repository; + private entity; + constructor(dataSource: DataSource, req: Request, entity) { + super(dataSource, req); + this.repository = this.getRepository(entity); + this.entity = entity; + } + + async findWithRank(options: RankListOptionDto): Promise<[RankListDto]> { + const queryBuilder = this.repository + .createQueryBuilder() + .select(['b.rank', 'b.user_id', 'b.point', 'b.nickname']) + .distinct(true) + .from((sub) => { + return sub + .select('RANK() OVER (ORDER BY a.point DESC)', 'rank') + .addSelect('a.user_id', 'user_id') + .addSelect('a.point', 'point') + .addSelect('u.nickname', 'nickname') + .from(this.entity, 'a') + .innerJoin(User, 'u', 'a.user_id = u.user_id') + .where(this.createClassificationOption(options)); + }, 'b') + .where(this.createCursorOption(options)) + .orderBy('point', 'DESC') + .addOrderBy('user_id') + .limit(3); + return await (>queryBuilder.getRawMany()); + } + + createCursorOption(options: RankListOptionDto) { + if (!options.cursorPoint && !options.cursorUserId) { + return 'b.point > -1'; + } else { + return `b.point < ${options.cursorPoint} or b.point = ${options.cursorPoint} AND b.user_id > '${options.cursorUserId}'`; + } + } + + createClassificationOption(options: PointFindDto) { + if (options.major != null) { + return `u.major like '${options.major}'`; + } else { + return `u.id > 0`; + } + } +} From 72a86c330edc083e796f752c049c570810ac7188 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 23:42:47 +0900 Subject: [PATCH 13/21] =?UTF-8?q?Refactor:=20AlgorithmRepository=EC=9D=98?= =?UTF-8?q?=20=EB=9E=AD=ED=81=AC=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?=EC=83=81=EC=86=8D=20=EB=B0=9B=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/repository/algorithm.repository.ts | 37 +++------------------ src/stat/service/algorithm.service.ts | 2 +- 2 files changed, 6 insertions(+), 33 deletions(-) diff --git a/src/stat/repository/algorithm.repository.ts b/src/stat/repository/algorithm.repository.ts index d404976..44cab47 100644 --- a/src/stat/repository/algorithm.repository.ts +++ b/src/stat/repository/algorithm.repository.ts @@ -1,18 +1,16 @@ -import { BaseRepository } from '../../utils/base.repository'; import { Inject, Injectable, Scope } from '@nestjs/common'; -import { DataSource, Repository } from 'typeorm'; +import { DataSource } from 'typeorm'; import { REQUEST } from '@nestjs/core'; import { Algorithm } from '../../Entity/algorithm'; -import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; +import { RankListOptionDto } from '../dto/rank-list-option.dto'; import { User } from '../../Entity/user'; import { PointFindDto } from '../dto/rank-find.dto'; +import { StatRepository } from '../../utils/stat.repository'; @Injectable({ scope: Scope.REQUEST }) -export class AlgorithmRepository extends BaseRepository { - private repository: Repository; +export class AlgorithmRepository extends StatRepository { constructor(dataSource: DataSource, @Inject(REQUEST) req: Request) { - super(dataSource, req); - this.repository = this.getRepository(Algorithm); + super(dataSource, req, Algorithm); } async save(algorithm: Algorithm) { @@ -22,31 +20,6 @@ export class AlgorithmRepository extends BaseRepository { async findOneById(userId: string) { return await this.repository.findOneBy({ userId: userId }); } - - async findAlgorithmWithRank( - options: RankListOptionDto, - ): Promise<[RankListDto]> { - const queryBuilder = this.repository - .createQueryBuilder() - .select(['b.rank', 'b.user_id', 'b.point', 'b.nickname']) - .distinct(true) - .from((sub) => { - return sub - .select('RANK() OVER (ORDER BY a.point DESC)', 'rank') - .addSelect('a.user_id', 'user_id') - .addSelect('a.point', 'point') - .addSelect('u.nickname', 'nickname') - .from(Algorithm, 'a') - .innerJoin(User, 'u', 'a.user_id = u.user_id') - .where(this.createClassificationOption(options)); - }, 'b') - .where(this.createCursorOption(options)) - .orderBy('point', 'DESC') - .addOrderBy('user_id') - .limit(3); - return await (>queryBuilder.getRawMany()); - } - public async findIndividualAlgorithmRank( userId: string, options: PointFindDto, diff --git a/src/stat/service/algorithm.service.ts b/src/stat/service/algorithm.service.ts index 89f1080..17ff33c 100644 --- a/src/stat/service/algorithm.service.ts +++ b/src/stat/service/algorithm.service.ts @@ -34,7 +34,7 @@ export class AlgorithmService { ) { throw new BadRequestException('Cursor Element Must Be Two'); } - return await this.algorithmRepository.findAlgorithmWithRank(options); + return await this.algorithmRepository.findWithRank(options); } async createAlgorithm(userId: string, bojId: string) { From 809af4d8595693a183a4950ea17a754229670dea Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 23:44:22 +0900 Subject: [PATCH 14/21] =?UTF-8?q?Refactor:=20GithubRepository=20=EB=9E=AD?= =?UTF-8?q?=ED=81=AC=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20=EC=83=81?= =?UTF-8?q?=EC=86=8D=20=EB=B0=9B=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/repository/github.repository.ts | 52 ++---------------------- src/stat/service/github.service.ts | 2 +- 2 files changed, 5 insertions(+), 49 deletions(-) diff --git a/src/stat/repository/github.repository.ts b/src/stat/repository/github.repository.ts index 1b071b1..00ddfdd 100644 --- a/src/stat/repository/github.repository.ts +++ b/src/stat/repository/github.repository.ts @@ -1,19 +1,15 @@ -import { BaseRepository } from '../../utils/base.repository'; import { Inject, Injectable } from '@nestjs/common'; import { Github } from '../../Entity/github'; -import { DataSource, Repository } from 'typeorm'; +import { DataSource } from 'typeorm'; import { REQUEST } from '@nestjs/core'; -import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { User } from '../../Entity/user'; import { PointFindDto } from '../dto/rank-find.dto'; +import { StatRepository } from '../../utils/stat.repository'; @Injectable() -export class GithubRepository extends BaseRepository { - private repository: Repository; - +export class GithubRepository extends StatRepository { constructor(dataSource: DataSource, @Inject(REQUEST) req: Request) { - super(dataSource, req); - this.repository = this.getRepository(Github); + super(dataSource, req, Github); } public async save(github: Github) { @@ -64,44 +60,4 @@ export class GithubRepository extends BaseRepository { return await queryBuilder.getRawOne(); } - - createClassificationOption(options: PointFindDto) { - if (options.major != null) { - return `u.major like '${options.major}'`; - } else { - return `u.id > 0`; - } - } - - async findGithubWithRank( - options: RankListOptionDto, - ): Promise<[RankListDto]> { - const queryBuilder = this.repository - .createQueryBuilder() - .select(['b.rank', 'b.user_id', 'b.point', 'b.nickname']) - .distinct(true) - .from((sub) => { - return sub - .select('RANK() OVER (ORDER BY a.point DESC)', 'rank') - .addSelect('a.user_id', 'user_id') - .addSelect('a.point', 'point') - .addSelect('u.nickname', 'nickname') - .from(Github, 'a') - .innerJoin(User, 'u', 'a.user_id = u.user_id') - .where(this.createClassificationOption(options)); - }, 'b') - .where(this.createCursorOption(options)) - .orderBy('point', 'DESC') - .addOrderBy('user_id') - .limit(3); - return await (>queryBuilder.getRawMany()); - } - - createCursorOption(options: RankListOptionDto) { - if (!options.cursorPoint && !options.cursorUserId) { - return 'b.point > -1'; - } else { - return `b.point < ${options.cursorPoint} or b.point = ${options.cursorPoint} AND b.user_id > '${options.cursorUserId}'`; - } - } } diff --git a/src/stat/service/github.service.ts b/src/stat/service/github.service.ts index 9976df4..ee53cb9 100644 --- a/src/stat/service/github.service.ts +++ b/src/stat/service/github.service.ts @@ -166,6 +166,6 @@ export class GithubService { ) { throw new BadRequestException('Cursor Element Must Be Two'); } - return await this.githubRepository.findGithubWithRank(options); + return await this.githubRepository.findWithRank(options); } } From 540bc5d8b6290d49eb508ef2b089e9fa9b86421d Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 23:47:26 +0900 Subject: [PATCH 15/21] =?UTF-8?q?Refactor:=20GradeRepository=20=EB=9E=AD?= =?UTF-8?q?=ED=81=AC=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20=EC=83=81?= =?UTF-8?q?=EC=86=8D=20=EB=B0=9B=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/repository/grade.repository.ts | 52 ++----------------------- src/stat/service/grade.service.ts | 2 +- 2 files changed, 5 insertions(+), 49 deletions(-) diff --git a/src/stat/repository/grade.repository.ts b/src/stat/repository/grade.repository.ts index 4fd3432..8f8a285 100644 --- a/src/stat/repository/grade.repository.ts +++ b/src/stat/repository/grade.repository.ts @@ -1,19 +1,15 @@ -import { BaseRepository } from '../../utils/base.repository'; import { Inject, Injectable } from '@nestjs/common'; -import { DataSource, Repository } from 'typeorm'; +import { DataSource } from 'typeorm'; import { REQUEST } from '@nestjs/core'; import { Grade } from '../../Entity/grade'; -import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { User } from '../../Entity/user'; import { PointFindDto } from '../dto/rank-find.dto'; +import { StatRepository } from '../../utils/stat.repository'; @Injectable() -export class GradeRepository extends BaseRepository { - private repository: Repository; - +export class GradeRepository extends StatRepository { constructor(dataSource: DataSource, @Inject(REQUEST) req: Request) { - super(dataSource, req); - this.repository = this.getRepository(Grade); + super(dataSource, req, Grade); } public async save(grade: Grade) { @@ -59,44 +55,4 @@ export class GradeRepository extends BaseRepository { return await queryBuilder.getRawOne(); } - - async findGradeWithRank( - options: RankListOptionDto, - ): Promise<[RankListDto]> { - const queryBuilder = this.repository - .createQueryBuilder() - .select(['b.rank', 'b.user_id', 'b.point', 'b.nickname']) - .distinct(true) - .from((sub) => { - return sub - .select('RANK() OVER (ORDER BY a.point DESC)', 'rank') - .addSelect('a.user_id', 'user_id') - .addSelect('a.point', 'point') - .addSelect('u.nickname', 'nickname') - .from(Grade, 'a') - .innerJoin(User, 'u', 'a.user_id = u.user_id') - .where(this.createClassificationOption(options)); - }, 'b') - .where(this.createCursorOption(options)) - .orderBy('point', 'DESC') - .addOrderBy('user_id') - .limit(3); - return await (>queryBuilder.getRawMany()); - } - - createCursorOption(options: RankListOptionDto) { - if (!options.cursorPoint && !options.cursorUserId) { - return 'b.point > -1'; - } else { - return `b.point < ${options.cursorPoint} or b.point = ${options.cursorPoint} AND b.user_id > '${options.cursorUserId}'`; - } - } - - createClassificationOption(options: PointFindDto) { - if (options.major != null) { - return `u.major like '${options.major}'`; - } else { - return `u.id > 0`; - } - } } diff --git a/src/stat/service/grade.service.ts b/src/stat/service/grade.service.ts index 661edaa..519133d 100644 --- a/src/stat/service/grade.service.ts +++ b/src/stat/service/grade.service.ts @@ -73,6 +73,6 @@ export class GradeService { ) { throw new BadRequestException('Cursor Element Must Be Two'); } - return await this.gradeRepository.findGradeWithRank(options); + return await this.gradeRepository.findWithRank(options); } } From 894de0130cec03a6157761763e7d0cb456417637 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Fri, 19 Apr 2024 23:48:53 +0900 Subject: [PATCH 16/21] =?UTF-8?q?Refactor:=20TotalRepository=20=EB=9E=AD?= =?UTF-8?q?=ED=81=AC=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20=EC=83=81?= =?UTF-8?q?=EC=86=8D=20=EB=B0=9B=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/repository/total.repository.ts | 52 ++----------------------- src/stat/service/total.service.ts | 2 +- 2 files changed, 5 insertions(+), 49 deletions(-) diff --git a/src/stat/repository/total.repository.ts b/src/stat/repository/total.repository.ts index dd24c67..1854da7 100644 --- a/src/stat/repository/total.repository.ts +++ b/src/stat/repository/total.repository.ts @@ -1,19 +1,15 @@ -import { BaseRepository } from '../../utils/base.repository'; -import { DataSource, Repository } from 'typeorm'; +import { DataSource } from 'typeorm'; import { Inject } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { TotalPoint } from '../../Entity/totalPoint'; -import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { Algorithm } from '../../Entity/algorithm'; import { User } from '../../Entity/user'; import { PointFindDto } from '../dto/rank-find.dto'; +import { StatRepository } from '../../utils/stat.repository'; -export class TotalRepository extends BaseRepository { - private repository: Repository; - +export class TotalRepository extends StatRepository { constructor(dataSource: DataSource, @Inject(REQUEST) req: Request) { - super(dataSource, req); - this.repository = this.getRepository(TotalPoint); + super(dataSource, req, TotalPoint); } async findOneById(userId: string) { @@ -50,44 +46,4 @@ export class TotalRepository extends BaseRepository { return await queryBuilder.getRawOne(); } - - createClassificationOption(options: PointFindDto) { - if (options.major != null) { - return `u.major like '${options.major}'`; - } else { - return `u.id > 0`; - } - } - - async findTotalWithRank( - options: RankListOptionDto, - ): Promise<[RankListDto]> { - const queryBuilder = this.repository - .createQueryBuilder() - .select(['b.rank', 'b.user_id', 'b.point', 'b.nickname']) - .distinct(true) - .from((sub) => { - return sub - .select('RANK() OVER (ORDER BY a.point DESC)', 'rank') - .addSelect('a.user_id', 'user_id') - .addSelect('a.point', 'point') - .addSelect('u.nickname', 'nickname') - .from(TotalPoint, 'a') - .innerJoin(User, 'u', 'a.user_id = u.user_id') - .where(this.createClassificationOption(options)); - }, 'b') - .where(this.createCursorOption(options)) - .orderBy('point', 'DESC') - .addOrderBy('user_id') - .limit(3); - return await (>queryBuilder.getRawMany()); - } - - createCursorOption(options: RankListOptionDto) { - if (!options.cursorPoint && !options.cursorUserId) { - return 'b.point > -1'; - } else { - return `b.point < ${options.cursorPoint} or b.point = ${options.cursorPoint} AND b.user_id > '${options.cursorUserId}'`; - } - } } diff --git a/src/stat/service/total.service.ts b/src/stat/service/total.service.ts index 5354441..b373f96 100644 --- a/src/stat/service/total.service.ts +++ b/src/stat/service/total.service.ts @@ -38,7 +38,7 @@ export class TotalService { ) { throw new BadRequestException('Cursor Element Must Be Two'); } - return await this.totalRepository.findTotalWithRank(options); + return await this.totalRepository.findWithRank(options); } async createTotalPoint(userId: string) { From 7b8b90a21a92aa7d347244c078a7fec1326eebb5 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Sat, 20 Apr 2024 00:20:57 +0900 Subject: [PATCH 17/21] =?UTF-8?q?Feat:=20StatRepository=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EA=B0=9C=EC=9D=B8=EB=93=B1=EC=88=98=EB=A5=BC=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=ED=95=98=EB=8A=94=20findIndividualRank=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/stat.repository.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/utils/stat.repository.ts b/src/utils/stat.repository.ts index 3116cc8..ec2b2e6 100644 --- a/src/utils/stat.repository.ts +++ b/src/utils/stat.repository.ts @@ -1,8 +1,5 @@ import { BaseRepository } from './base.repository'; import { DataSource, Repository } from 'typeorm'; -import { Algorithm } from '../Entity/algorithm'; -import { Inject } from '@nestjs/common'; -import { REQUEST } from '@nestjs/core'; import { RankListDto, RankListOptionDto, @@ -41,6 +38,24 @@ export class StatRepository extends BaseRepository { return await (>queryBuilder.getRawMany()); } + public async findIndividualRank(userId: string, options: PointFindDto) { + const queryBuilder = this.repository + .createQueryBuilder() + .select(['b.rank', 'b.user_id']) + .distinct(true) + .from((sub) => { + return sub + .select('RANK() OVER (ORDER BY a.point DESC)', 'rank') + .addSelect('a.user_id', 'user_id') + .from(this.entity, 'a') + .innerJoin(User, 'u', 'a.user_id = u.user_id') + .addSelect('u.major', 'major') + .where(this.createClassificationOption(options)); + }, 'b') + .where(`b.user_id = '${userId}'`); + + return await queryBuilder.getRawOne(); + } createCursorOption(options: RankListOptionDto) { if (!options.cursorPoint && !options.cursorUserId) { return 'b.point > -1'; From 06f4fc512b11fb3dc91af058ed4930f34d06e2ad Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Sat, 20 Apr 2024 00:21:49 +0900 Subject: [PATCH 18/21] =?UTF-8?q?Fix:=20=EC=8A=A4=EC=9B=A8=EA=B1=B0?= =?UTF-8?q?=EC=97=90=20path=20=EB=B3=80=EC=88=98=EA=B0=80=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/rank.controller.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/stat/rank.controller.ts b/src/stat/rank.controller.ts index 128fe6d..61d053d 100644 --- a/src/stat/rank.controller.ts +++ b/src/stat/rank.controller.ts @@ -127,7 +127,6 @@ export class RankController { return await this.totalService.getTotalRank(options); } - @Get('/users/:id') @ApiTags('rank') @ApiOperation({ summary: '유저의 각 부문 별 랭킹 API', @@ -148,10 +147,14 @@ export class RankController { @ApiInternalServerErrorResponse({ description: '서버 오류', }) - async findUsersRank(@Param('id') userId, @Query() options: PointFindDto) { + @Get('/users/:id') + async findUsersRank( + @Param('id') userId: string, + @Query() options: PointFindDto, + ) { const user = await this.userService.findUserByUserId(userId); - if (options && user.major !== options.major) { + if (options.major && user.major !== options.major) { return new RankFindDto(null, null, null, null); } else { const algorithmRank = From 5d8ef50ccaefbdfd7aac90e201713e3a3691c66f Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Sat, 20 Apr 2024 00:24:33 +0900 Subject: [PATCH 19/21] =?UTF-8?q?Refactor:=20=EA=B0=81=20repository?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EA=B3=B5=ED=86=B5=EB=90=98=EC=97=88?= =?UTF-8?q?=EB=8D=98=20=EA=B0=9C=EC=9D=B8=20=EB=9E=AD=ED=81=AC=20=EC=B0=BE?= =?UTF-8?q?=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20=EC=83=81?= =?UTF-8?q?=EC=86=8D=20=EB=B0=9B=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/repository/algorithm.repository.ts | 2 +- src/stat/repository/github.repository.ts | 24 ------------------- src/stat/repository/grade.repository.ts | 24 ------------------- src/stat/repository/total.repository.ts | 26 --------------------- src/stat/service/algorithm.service.ts | 2 +- src/stat/service/github.service.ts | 5 +--- src/stat/service/grade.service.ts | 5 +--- src/stat/service/total.service.ts | 5 +--- 8 files changed, 5 insertions(+), 88 deletions(-) diff --git a/src/stat/repository/algorithm.repository.ts b/src/stat/repository/algorithm.repository.ts index 44cab47..1ec932c 100644 --- a/src/stat/repository/algorithm.repository.ts +++ b/src/stat/repository/algorithm.repository.ts @@ -38,7 +38,7 @@ export class AlgorithmRepository extends StatRepository { .addSelect('u.major', 'major') .where(this.createClassificationOption(options)); }, 'b') - .where(`b.user_id = ${userId}`); + .where(`b.user_id = '${userId}'`); return await queryBuilder.getRawOne(); } diff --git a/src/stat/repository/github.repository.ts b/src/stat/repository/github.repository.ts index 00ddfdd..31216ec 100644 --- a/src/stat/repository/github.repository.ts +++ b/src/stat/repository/github.repository.ts @@ -2,8 +2,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { Github } from '../../Entity/github'; import { DataSource } from 'typeorm'; import { REQUEST } from '@nestjs/core'; -import { User } from '../../Entity/user'; -import { PointFindDto } from '../dto/rank-find.dto'; import { StatRepository } from '../../utils/stat.repository'; @Injectable() @@ -38,26 +36,4 @@ export class GithubRepository extends StatRepository { public async findAll() { return await this.repository.find(); } - - public async findIndividualGithubRank( - userId: string, - options: PointFindDto, - ) { - const queryBuilder = this.repository - .createQueryBuilder() - .select(['b.rank', 'b.user_id']) - .distinct(true) - .from((sub) => { - return sub - .select('RANK() OVER (ORDER BY g.point DESC)', 'rank') - .addSelect('g.user_id', 'user_id') - .addSelect('g.point', 'point') - .from(Github, 'g') - .innerJoin(User, 'u', 'g.user_id = u.user_id') - .where(this.createClassificationOption(options)); - }, 'b') - .where(`b.user_id = ${userId}`); - - return await queryBuilder.getRawOne(); - } } diff --git a/src/stat/repository/grade.repository.ts b/src/stat/repository/grade.repository.ts index 8f8a285..2643d45 100644 --- a/src/stat/repository/grade.repository.ts +++ b/src/stat/repository/grade.repository.ts @@ -2,8 +2,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { DataSource } from 'typeorm'; import { REQUEST } from '@nestjs/core'; import { Grade } from '../../Entity/grade'; -import { User } from '../../Entity/user'; -import { PointFindDto } from '../dto/rank-find.dto'; import { StatRepository } from '../../utils/stat.repository'; @Injectable() @@ -33,26 +31,4 @@ export class GradeRepository extends StatRepository { public async delete(id: string) { await this.repository.delete({ userId: id }); } - - public async findIndividualGradeRank( - userId: string, - options: PointFindDto, - ) { - const queryBuilder = this.repository - .createQueryBuilder() - .select(['b.rank', 'b.user_id']) - .distinct(true) - .from((sub) => { - return sub - .select('RANK() OVER (ORDER BY g.point DESC)', 'rank') - .addSelect('g.user_id', 'user_id') - .addSelect('g.point', 'point') - .from(Grade, 'g') - .innerJoin(User, 'u', 'g.user_id = u.user_id') - .where(this.createClassificationOption(options)); - }, 'b') - .where(`b.user_id = ${userId}`); - - return await queryBuilder.getRawOne(); - } } diff --git a/src/stat/repository/total.repository.ts b/src/stat/repository/total.repository.ts index 1854da7..1977e62 100644 --- a/src/stat/repository/total.repository.ts +++ b/src/stat/repository/total.repository.ts @@ -2,9 +2,6 @@ import { DataSource } from 'typeorm'; import { Inject } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { TotalPoint } from '../../Entity/totalPoint'; -import { Algorithm } from '../../Entity/algorithm'; -import { User } from '../../Entity/user'; -import { PointFindDto } from '../dto/rank-find.dto'; import { StatRepository } from '../../utils/stat.repository'; export class TotalRepository extends StatRepository { @@ -23,27 +20,4 @@ export class TotalRepository extends StatRepository { async save(total: TotalPoint) { return await this.repository.save(total); } - - public async findIndividualAlgorithmRank( - userId: string, - options: PointFindDto, - ) { - const queryBuilder = this.repository - .createQueryBuilder() - .select(['b.rank', 'b.user_id', 'b.major']) - .distinct(true) - .from((sub) => { - return sub - .select('RANK() OVER (ORDER BY a.point DESC)', 'rank') - .addSelect('a.user_id', 'user_id') - .addSelect('a.point', 'point') - .from(Algorithm, 'a') - .innerJoin(User, 'u', 'a.user_id = u.user_id') - .addSelect('u.major', 'major') - .where(this.createClassificationOption(options)); - }, 'b') - .where(`b.user_id = ${userId}`); - - return await queryBuilder.getRawOne(); - } } diff --git a/src/stat/service/algorithm.service.ts b/src/stat/service/algorithm.service.ts index 17ff33c..8a9c32e 100644 --- a/src/stat/service/algorithm.service.ts +++ b/src/stat/service/algorithm.service.ts @@ -123,7 +123,7 @@ export class AlgorithmService { userId: string, options: PointFindDto, ) { - return await this.algorithmRepository.findIndividualAlgorithmRank( + return await this.algorithmRepository.findIndividualRank( userId, options, ); diff --git a/src/stat/service/github.service.ts b/src/stat/service/github.service.ts index ee53cb9..5a7d0f8 100644 --- a/src/stat/service/github.service.ts +++ b/src/stat/service/github.service.ts @@ -134,10 +134,7 @@ export class GithubService { userId: string, options: PointFindDto, ) { - return await this.githubRepository.findIndividualGithubRank( - userId, - options, - ); + return await this.githubRepository.findIndividualRank(userId, options); } // public async redirect(code: string) { diff --git a/src/stat/service/grade.service.ts b/src/stat/service/grade.service.ts index 519133d..88f8ed5 100644 --- a/src/stat/service/grade.service.ts +++ b/src/stat/service/grade.service.ts @@ -60,10 +60,7 @@ export class GradeService { } public async getIndividualGradeRank(userId: string, options: PointFindDto) { - return await this.gradeRepository.findIndividualGradeRank( - userId, - options, - ); + return await this.gradeRepository.findIndividualRank(userId, options); } async getGradeRank(options: RankListOptionDto): Promise<[RankListDto]> { diff --git a/src/stat/service/total.service.ts b/src/stat/service/total.service.ts index b373f96..8982193 100644 --- a/src/stat/service/total.service.ts +++ b/src/stat/service/total.service.ts @@ -68,9 +68,6 @@ export class TotalService { } public async getIndividualTotalRank(userId: string, options: PointFindDto) { - return await this.totalRepository.findIndividualAlgorithmRank( - userId, - options, - ); + return await this.totalRepository.findIndividualRank(userId, options); } } From e4fd0ad64bc48c7dba38c223ac7a332dbab34c10 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Sat, 20 Apr 2024 00:30:31 +0900 Subject: [PATCH 20/21] =?UTF-8?q?Refactor:=20rank=20=EC=97=90=EC=84=9C=20u?= =?UTF-8?q?ser=5Fid=EB=A5=BC=20userId=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/dto/rank-list-option.dto.ts | 2 +- src/utils/stat.repository.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/stat/dto/rank-list-option.dto.ts b/src/stat/dto/rank-list-option.dto.ts index 8850715..85e3d01 100644 --- a/src/stat/dto/rank-list-option.dto.ts +++ b/src/stat/dto/rank-list-option.dto.ts @@ -21,7 +21,7 @@ export class RankListDto { rank: number; @ApiProperty() - user_id: string; + userId: string; @ApiProperty() point: number; diff --git a/src/utils/stat.repository.ts b/src/utils/stat.repository.ts index ec2b2e6..f7b5982 100644 --- a/src/utils/stat.repository.ts +++ b/src/utils/stat.repository.ts @@ -19,7 +19,8 @@ export class StatRepository extends BaseRepository { async findWithRank(options: RankListOptionDto): Promise<[RankListDto]> { const queryBuilder = this.repository .createQueryBuilder() - .select(['b.rank', 'b.user_id', 'b.point', 'b.nickname']) + .select(['b.rank', 'b.point', 'b.nickname']) + .addSelect('b.user_id', 'userId') .distinct(true) .from((sub) => { return sub @@ -33,7 +34,7 @@ export class StatRepository extends BaseRepository { }, 'b') .where(this.createCursorOption(options)) .orderBy('point', 'DESC') - .addOrderBy('user_id') + .addOrderBy('userId') .limit(3); return await (>queryBuilder.getRawMany()); } From a3bad4f42ed36d56e7f363c403973ae604b33926 Mon Sep 17 00:00:00 2001 From: koomin1227 Date: Sat, 20 Apr 2024 00:54:10 +0900 Subject: [PATCH 21/21] =?UTF-8?q?Feat:=20TotalPoint=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stat/dto/stat-find.dto.ts | 3 +++ src/stat/service/total.service.ts | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/stat/dto/stat-find.dto.ts b/src/stat/dto/stat-find.dto.ts index d8681d4..2d18367 100644 --- a/src/stat/dto/stat-find.dto.ts +++ b/src/stat/dto/stat-find.dto.ts @@ -9,4 +9,7 @@ export class StatFindDto { @ApiProperty() grade: number; + + @ApiProperty() + totalPoint: number; } diff --git a/src/stat/service/total.service.ts b/src/stat/service/total.service.ts index 8982193..269474a 100644 --- a/src/stat/service/total.service.ts +++ b/src/stat/service/total.service.ts @@ -9,6 +9,7 @@ import { Grade } from '../../Entity/grade'; import { Algorithm } from '../../Entity/algorithm'; import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto'; import { PointFindDto } from '../dto/rank-find.dto'; +import { StatFindDto } from '../dto/stat-find.dto'; @Injectable() export class TotalService { @@ -19,15 +20,17 @@ export class TotalService { private gradeService: GradeService, ) {} - async findStat(userId: string) { + async findStat(userId: string): Promise { const github = await this.githubService.findGithub(userId); const algorithm = await this.algorithmService.findAlgorithm(userId); const grade = await this.gradeService.findGrade(userId); + const total = await this.totalRepository.findOneById(userId); return { githubPoint: github ? github.point : null, algorithmPoint: algorithm ? algorithm.point : null, grade: grade ? grade.grade : null, + totalPoint: grade ? total.point : null, }; }