TypeORM으로 쿼리 작성

TypeORM 쿼리 TypeORM에는 create, save, find, findOne, createQueryBuilder 등 있다. 복잡한 우리의 알고리즘을 위해 createQueryBuilder를 사용하자. 쿼리 설치하기 컨트롤러로 간다. 1 2 3 4 5 // reports.controller.ts @Get() getEstimate(@Query() query: GetEstimateDto) { return this.reportsService.createEstimate(query); } 서비스에 메서드를 추가하자 1 2 3 4 5 6 // reports.service.ts import { GetEstimateDto } from './dtos/get-estimate.dto'; createEstimate(estimateDto: GetEstimateDto) { return this.repo.createQueryBuilder().select('*').getRawMany(); } 우선은 모든 속성을 받도록 쿼리를 작성했다. 서버를 실행하고 API Client에서 만들어 놓은 추정치를 받는 요청을 보내보자. 속성들이 잘 오면 성공. ...

2023년 10월 10일 · 2 분 · 배준수

승인 시스템

기초적인 승인 시스템 제출된 보고서 중 무의미한 데이터를 방지하기 위해 ‘관리자’와 관리자의 승인 개념을 도입한다. 우선은 관리자는 배제한체 승인에 관해서만 구현한다. 우선 report.entity 파일에 속성을 추가하자 1 2 3 // report.entity.ts @Column({ default: false }) approved: boolean; 이후 컨트롤러에 관련 메서드를 추가한다. 1 2 3 // reports.controller.ts @Patch('/:id') approveReport(@Param('id') id: string, @Body() body: ApprovedReportDto) {} reports의 dtos 디렉토리에 새로운 dto를 추가하자. report dto 에도 approved 속성을 추가해야한다. ...

2023년 10월 10일 · 5 분 · 배준수

클러스터링 인덱스

책너두 6기 26일차 백은빈, 이성욱의 Real MySQL8.0 1권 p.267 ~ p.276 내용정리 08 인덱스 8.6.2 함수를 이용한 인덱스 다음과 같이 테이블의 구조를 변경하지 않고, 함수를 직접 사용하는 인덱스를 생성할 수 있다. 1 2 3 4 5 6 7 create table user( user_id BIGINT, first_name VARCHAR(10), last_name VARCHAR(10), PRIMARY KEY (user_id), INDEX ix_fullname ((concat(first_name,' ',last_name))) ); 함수를 직접 사용하는 인덱스는 테이블의 구조는 변경하지 않고, 검색을 빠르게 만들어준다. 제대로 활용하려면 반드시 조건절에 함수 기반 인덱스에 명시된 표현식이 그대로 사용돼야 한다. ...

2023년 10월 10일 · 2 분 · 배준수

Authentication, Cookie-session

Authentication Overview 인증 과정의 전체 흐름부터 살펴보자. 어떤 클라이언트가 애플리케이션에 요청하고 우리 서비스에 가입하려고 한다. 요청에는 eamil과 password가 들어있다. 서버는 이메일이 이미 이메일이 사용중인지 확인한다. 유저의 암호를 암호화한다. 새로운 유저 레코드를 저장한다. 요청에 대한 응답으로 유저의 id를 포함하는 쿠키를 되돌려보낸다. 브라우저는 자동적으로 쿠키를 저장하고 이후 클라이언트의 요청에 쿠키를 붙여준다. 유저는 reports를 보낸다. 여기엔 쿠키 포함 되어있고(쿠키 내에는 유저의 id가 포함되어 있다.) report를 위한 정보도 들어있다. 서버는 쿠키의 데이터가 임의로 조작되진 않았는지 확인한다. ...

2023년 10월 9일 · 7 분 · 배준수

Authentication와 Guard

Authentication Custom Decorator 만들기 handler에게 자동으로 현재 로그인한 유저를 알려주는 기능을 만들려고 한다. 우리는 기존의 @Session() 대신 새로운 우리만의 decorator를 만들 것이다. 우리가 만들 CurrentUser Decorator는 2가지가 필요할 것이다. Session Object : 요청한 유저의 id를 알아야 한다. UsersService Instance : 알아낸 id를 가진 사용자를 찾아야 하기 떄문이다. 우리는 Param decorators로 만들어야 한다. 하지만 Param decorators는 DI(종속성 주입) 시스템 외부에 있어서, UsersService 인스턴스를 받을 수 없다. 이 문제를 해결하기 위해 interceptor를 만든다. ...

2023년 10월 9일 · 3 분 · 배준수

단위 테스트

Unit Testing 유닛 테스트 과정 Fake UsersService를 만들어서 실행할 계획이다. 정상적으로 애플리케이션을 실행하면 DI 안에 많은 종속성을 넣어야 한다. 우린 새롭게 테스트를 위한 DI를 만드는데, 내부에는 Userss Service의 모든 메서드를 실행하는 클래스를 담는다. 이로서 어떤 단위(ex. Authentication, sign in 등)을 테스트하는데 종속성 주입에서 자유로워질 수 있다. Test 설정하기 users 디렉토리에 auth.service.spec.ts 파일을 만들자 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // auth.service.spec.ts import { Test } from '@nestjs/testing'; import { AuthService } from './auth.service'; import { UsersService } from './users.service'; it('can create an instance of auth service', async () => { // 새 DI container 생성 // 하지만 AUthService를 위한 종속성을 제공하지 않았으니 실행하면 오류가 뜰것이다. constmudle = await Testing.createTestingModule({ providers:[AuthService] }).compile(); const service = module.get(AuthService); expect(service).toBeDefined(); }); 터미널에서 npm run test:watch를 입력한다. 3개가 failed라고 뜰텐데, p를 누르고 auth.service.spec 을 입력한다. 그럼 이 파일만 테스트하여 1 failed라고 뜬다. ...

2023년 10월 9일 · 5 분 · 배준수

전문 검색 인덱스

책너두 6기 25일차 백은빈, 이성욱의 Real MySQL8.0 1권 p.258 ~ p.266 내용정리 08 인덱스 8.5 전문 검색 인덱스 현재까지 공부한 인덱스 알고리즘은 크지 않은 데이터나 이미 키워드화한 작은 값에 대한 인덱싱 알고리즘이다. 문서 전체에 대한 분석과 검색을 위한 이러한 인덱싱 알고리즘을 전문 검색(Full Text search) 인덱스 라고 한다. 이는 일반화된 기능의 명칭이다. 8.5.1 인덱스 알고리즘 전문 검색에서는 문서 본문의 내용에서 사용자가 검색하게 될 키워드를 분석해 내고, 빠른 검색용으로 사용할 수 있게 이러한 키워드로 인덱스를 구축한다. ...

2023년 10월 9일 · 3 분 · 배준수

2023년 10월 1주차 주간 기록

주간기록 날짜 2023년 10월 2일 ~ 2023년 10월 8일 계획 책너두 : Real MySQL 8.0 1권 매일 알고리즘 2문제 10월 2일 : 데브캠프 심화교육 강의 시작 10월 3일 : 48시간 과제 테스트 종료 10월 3일 : 인적성시험 10월 4일 : 알고리즘 스터디 10월 7일 : 코딩테스트 결과 데브캠프 심화교육 NestJS 강의 시작 GSAT 공부 시작 PCCP 공부 시작 회고 추석 중에 가장 바쁜 추석이었다. 근데 앞으로 더 바빠진다. NestJS 어렵지만 재밌다! ...

2023년 10월 8일 · 1 분 · 배준수

데이터 직렬화

Custom Data Serialization 응답에서 특정 속성 제거하기 비밀번호는 보안에서 중요한 만큼 응답에서 제외하는 것이 맞다. 이 과정을 진행해보자. 어떻게 다룰지는 Nest Document를 살펴볼 것. 현재 요청-응답 Flow는 다음과 같다. 요청이 발생한다. 컨트롤러로 이동 서비스로 이동 서비스가 Repository 이용하여 Entity instance를 컨트롤러에게 반환 이 인스턴스는 JSON으로 변환된다. Document에서 권장하는 방법 서비스에서 컨트롤러로 이동하는 Entity instance에 인스턴스를 plain object로 변경하는 것에 관한 규칙 라이브러리를 추가한다. class serializer interceptor 라는 decorator를 컨트롤러에서 추가한다. 이 interceptor는 들어오는 요청이나 내보내는 응답을 가로채서 entity를 plain object로 변경해준다. 우리의 경우 나가는 응답을 가로채서 entity를 라이브러리로 추가한 규칙에 맞게 plain object로 변경해줄것 결론적으로 우리는 일단 password는 빼고 response를 보내도록 코드를 추가해줄 예정이다. ...

2023년 10월 8일 · 7 분 · 배준수

Data 처리 및 저장

User Data Users service 이제 유저서비스를 다뤄보자. users.service.ts 파일을 수정하자 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // users.service.ts import { Injectable } from '@nestjs/common'; import { Repository } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm'; import { User } from './user.entity'; @Injectable() export class UsersService { // repo : argument name // Repository<User> : User type을 다루는 Repository에 접근하여 instance를 받는다. // @InjtectRepository(User) : DI 시스템에게 우리가 User Repository가 필요하다는것을 말하는 코드 // DI 시스템은 뒤에 Repository<User>부분에서 inject할 인스턴스가 무엇인지 파악하기 위해 // type annotation 한다. generic에는 잘 작동 안하니까 앞에 decorator를 통해 더 분명히 제공한 것. constructor(@InjectRepository(User) private repo: Repository<User>) {} // create는 service 내에서 받은 정보(email과 password)로 User Entity Instance를 만든다. // save는 entity instance를 실제 Database에 저장해준다. create(email: string, password: string) { const user = this.repo.create({ email, password }); return this.repo.save(user); } } 이제 컨트롤러에 넣어보자 ...

2023년 10월 7일 · 9 분 · 배준수