검색 기능 만들기

Today I Learned 날짜 2024년 6월 11일 화요일 내용 검색 쿼리 유저가 여러 댓글 중 무언가를 검색하거나, 데이터를 정렬하는 기능을 만들어야 했다. 기존 프로덕트 리뷰에 있는 건 너어어어무 복잡하고, 온갖 기능이 추가되어 유지보수가 힘들었다. 아예 다른 곳에서 쓰이는 것일 뿐더러 기능이나 검색 단위, 정렬 단위도 더 작은 범위라 최대한 깔끔하게 만들려고 했다. 정렬 방식이 조금 난해했는데, 정렬 기준이 2개인 경우가 있었기 떄문이다. 이번 인스타그램 댓글 가져오는 앱의 테이블 구조는 샵 → 페이스북 페이지 → 게시글 → 댓글 순서로 이루어졌으며 각각 일대다관계다. 댓글의 작성일자로 정렬할 때는 별 어려움이 없으나, 게시글 작성일자로 정렬할 떄는 꽤 어려웠다. 최근에 작성된 게시글 내의 댓글들을 먼저 가져오되, 같은 게시글 내에선 최근에 작성된 댓글이 먼저와야 했다. ...

2024년 6월 11일 · 1 분 · 배준수

쿼리문에 join이 필요한 경우

Today I Learned 날짜 2024년 2월 19일 월요일 내용 SQL 쿼리문에서 Join 그동안 쿼라를 이용해 관계(relationship)를 맺고 있는 여러 데이터를 가져올때 joinedload를 사용했다. 예를 들어, shop_detail 테이블에 있는 필드 use_ai는 우리 서비스에서 AI 기능을 사용하는 지를 나타낸다. id가 shop_id로 일치하는 Shop을 불러올 때, shop_detail도 같이 가져오기 위해 쿼리문을 다음과 같이 작성할 수 있다. 1 2 stmt = select(models.Shop).options(joinedload(models.Shop.shop_detail).where(models.Shop.id == shop_id) result = db.execute(stmt).scalar_one_or_none() 이 떄, result는 [models.Shop](http://models.Shop) 형식이겠지만, shop_detail을 참조할 수 있다. print(result.shop_detail.use_review)와 같은 형식으로! ...

2024년 2월 19일 · 1 분 · 배준수

세상에 나쁜 테스트는 있다.

Today I Learned 날짜 2023년 11월 24일 금요일 내용 테스트 코드 실행과 관련해서 Docker 내에서 실행해보라는 조언이 있어서 실행했다. 약간의 에러만 해결한 이후, 빠르게 테스트 코드 작성에 들어갈 수 있었다. Docker 내 실행 환경변수 건드리지말고 docker-compose exec 로 도커내에서 실행해보라는 태용님의 조언이 있었다. docker-compose exec service이름 실행내용 -v 을 통해 review 컨테이너 내에서 pytest를 진행했다. 하지만 오류로 테스트가 진행되지 않았다. 오류는 안뜨고 5성공, 5실패가 뜬다. 테스트 코드 작성 test_setup reviews_id 가 NOT NULL 인데 안들어가는 걸로 파악했다. Factory로 만들어진 review들의 id값을 확인할 수 있도록 코드를 수정했더니 모두 null값이 들어가 있었다. Factory 파일에선, Product는 id값을 1씩 증가하도록 배정해준반면 review에는 그러한 코드가 없었다. 둘다 모델 설정에는 BigInteger 이자 primary_key, index, unique로 지정되어있다. primary key가 True라면 자동으로 배정되야 하는지 나중에 찾아보자! 일단 factory처럼 증가하는 숫자를 넣었다. ⇒ 통과! test_get_widget 테스트 함수에서 parameter로 없는 것이 작성되어 있었다. 실제로 저 메서드를 찾아가보니 없길래 테스트 코드에서도 삭제해주었다. type으로 들어간 값은 schemas 파일에서 클래스를 가져와 그중 1개를 선택하도록 변경하였다. 기능 함수 내의 또다른 기능 함수의 반환이 예상과 다르다는 오류가 발생했다. 여기서 내가 기능 함수를 함부로 수정하면 안될것 같아 리더님께 여쭤봤는데, 현재 잘 작동되고 있는 메서드이고, 중요한 기능이라 시간을 들여 테스트 코드를 제대로 작성하는 쪽으로 진행하는게 좋다고 말씀해주셨다. 역시 “해도되나?” 는 안하는게 맞다. 테스트 코드 내 함수에서 param을 수정하였다. 기능 함수의 일부 params는 Query[None] 타입이다. 이는 값이 존재할 땐 Query로 처리하지만 없을땐 None으로 처리하겠다는 의미로 FastAPI에서만 쓰인다. 이 값이 데이터베이스 쿼리에 포함되면서 오류가 발생함. 실제 배포 서비스에서는 해당 값들이 어떤 이유로든 반드시 입력되어서 오류가 발생하지 않은 걸까? 일부 param들에 구체적인 값을 넣어줬더니 PASS 처리 되었다. 하지만 확실한 테스트를 위해 내 가설을 검증할 필요가 있다. 검증 사항 : 위 값들은 항상 주어질 수 밖에 없는 값인가? 모든 종류의 입력에서 무조건 설정하게 되있는 경우 입력이 없을때 넣을 값에 대한 로직이 존재하는 경우 기본값 있는 경우 따라서 이 값들은 입력값이 반드시 존재한다. schemas 상 범위 내의 값을 무작위로 넣어주면 될듯 ⇒ 통과 회고 이번에는 테스트 해야 할 함수들이 정상적으로 작동하고 있다는 확신이 있기 때문에 테스트 코드만 집중적으로 공략할 수 있었다. 만약 내가 방금 만들어낸 코드의 테스트가 실패했을 때, 내 테스트 코드를 신뢰할 수 없다면 오히려 코드의 정확성을 망치게 될 것 같다. 확실하게 무엇을 테스트 해야하는지, 공부했던 규칙들을 지키면서 신뢰성 있는 테스트 코드를 공부하자. ...

2023년 11월 24일 · 2 분 · 배준수

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 분 · 배준수