typeORM의 Entity를 연계한 createQueryBuilder 등을 지향하며, 최대한 직접적인 QueryRunner 방식 지양
삭제 및 비공개 댓글 가림
json 출력시 불필요한 요소 제거 (특히 Date 타입에서 !! )
가장 오랜시간을 지연시켰던 Blocker
typeORM createQueryBuilder 메소드로 출력시
1
2
2023-02-14T08:55:24.090Z// ^ ^^^^ <- 거추장스럽다.
이런 식으로 나오는 문제가 있는데 꽤나 씨름했다.
우선 Entity의 Date type은 datetime이 아닌 timestamp로 했다. mySQL에서의 출력은 DB가 설치된 서버의 시간대를 따르기에
아래와 같이 문제가 없다.
1
select*fromcommentswherefeedId=1
1
2
2023-02-1417:55:24.106558-- 이게 실제 한국 시간
문제는,
typeORM에서의 repository + createQueryBuilder를 이용한 직접 출력이다.
typeORM의 .find나 createQueryBuilder 메소드를 통해 출력을 하게 되면 ISO 8601 형식으로 내보내지기 때문에 먼저 보여줬던 예와 같이 문제가 생기는데 다시 정리하면 아래와 같다.
시간대 안맞음 (실제 시간은 17:55:24)
시간대 앞 뒤로 T, 090Z와 같은 부가요소가 함께 출력
현재 데이터를 출력하려는 query는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
exportconstCommentRepository=dataSource.getRepository(Comment).extend({asyncgetCommentList(id: number){returnawaitthis.createQueryBuilder('comment').leftJoinAndSelect('comment.children','children').leftJoinAndSelect('comment.user','user').leftJoinAndSelect('comment.feed','feed').leftJoinAndSelect('children.user','childrenUser').leftJoinAndSelect('children.feed','childrenFeed').where('comment.feed = :id',{id}).andWhere('comment.parentId IS NULL').orderBy('comment.id','ASC').addOrderBy('children.id','ASC').setParameter('id',id).getMany();},}
우선, 이를 local의 시간대로 맞추기 위해 아래와 같이 DataSource 설정에 timezone: 'Z' 를 추가하여 local 시간대로 출력되게끔 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
constdataSource=newDataSource({type:process.env.TYPEORM_CONNECTION,host: process.env.TYPEORM_HOST,port: process.env.TYPEORM_PORT,username: process.env.TYPEORM_USERNAME,password: process.env.TYPEORM_PASSWORD,database: process.env.TYPEORM_DATABASE,entities:[__dirname+'/../**/*.entity.{js,ts}'],timezone:'Z',// <-- 이렇게 추가
logging: Boolean(process.env.TYPEORM_LOGGING),synchronize: Boolean(process.env.TYPEORM_SYNCHRONIZE),charset:'utf8mb4',});
1
2
// 출력시,
2023-02-14T17:55:24.106Z
자 이제 시간대는 맞춰졌다.
2. 시간 구분자 제거
수정 전 내용 보기
다음은 문제의 저 T와 Z를 날려보자.
1
dateStrings: true,
DataSouce 연결 설정에 이걸 넣어준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
constdataSource=newDataSource({type:process.env.TYPEORM_CONNECTION,host: process.env.TYPEORM_HOST,port: process.env.TYPEORM_PORT,username: process.env.TYPEORM_USERNAME,password: process.env.TYPEORM_PASSWORD,database: process.env.TYPEORM_DATABASE,entities:[__dirname+'/../**/*.entity.{js,ts}'],timezone:'Z',dateStrings: true,// <-- 이렇게 추가
logging: Boolean(process.env.TYPEORM_LOGGING),synchronize: Boolean(process.env.TYPEORM_SYNCHRONIZE),charset:'utf8mb4',})
그리고 다시 출력을 해보면
1
2023-02-1417:55:24.106558
드디어 불필요한 알파벳은 사라졌다…라기보단,그런데 더 거추장스럽게도 밀리초(?)로 바뀌었다. 이제 이걸 제거해보자!
3. 정밀 초단위는 제거하고 시,분까지만 출력
여기서 정말 많이 찾아보고 공부했다.
typeORM의 queryRunner를 사용하거나,
createQueryBuilder에서 getRawMany()를 사용해 자료를 뽑아낸다면,
mySQL의 출력방식을 따르기때문에 SQL의 query문에 직접적인 수정을 가하여 컬럼값을 조정할 수가 있다.
(또는 toISOString()과 같은 메소드를 사용하여도 된다.)
하지만, 위에서 쓰고 있는 Entity에서 그대로 가져오는 getMany() 메소드를 이용해 자료를 가져오게 되면,
이런 방법이 불가하다.
이것도 확실한지는 모르겠는데 며칠을 찾아보고 시도해본 결과,
TypeORM의 getRawMany() 메서드는 쿼리 결과를 직접적으로 반환하는 반면, getMany() 메서드는 Entity 객체를 반환한다.
때문에 select <column>에 바로 수정을 가하게 되면 Entity의 type을 그대로 가져다 쓰는 특성상, 이 컬럼의 type error가 난다.
즉, select 또는 addSelect로 Alias하거나 수정을 함과 동시에 출력이 되지 않고 되려 해당 컬럼이 사라진다.
이러한 상태로의 해결방법은 Entity에서 직접 Alias 해줘야 하는데, 또 이렇게 되면 CreateDateColumn의 데코레이션 default 옵션이 깨진다.(피나는 시도 결과 ;; ㅠ)
때문에 결국 양자택일을 하는 수밖에 없었다.
getMany() 방식을 포기하거나,
service단에서 복잡하지만 수정을 가한다.
굳이 getMany() 방식을 고집하는 이유는 다음과 같다.
현재 저 코드 Comment Entity에서 가져오며, 해당 Entity는 parent와 children<Comment[]>의 자기참조 컬럼을 가지고 있는 Tree 구조로 이루어져 있다. 그리고 typeORM의 createQueryBuilder는 이 구조 특성을 그대로 살려서 출력이 가능하다.
반대로 query runner 방식으로 처리하여 같은 tree 구조를 출력하려면, repository단에서 굉장히 지독히도 가독성이 떨어지는 코드로 구현된다(물론 현재의 내 수준에서;;).1 typeORM의 Tree 방식으로 출력가능한 getMany() 메소드를 포기하게 된다면, repository단에서의 query가 생각보다 복잡하게 된다.
추후 유지보수의 가능성을 염두에 둔다.
대댓글 뿐만 아니라, 대대댓글 등의 무한 대댓글 구조역시 가능하도록 진행을 하는데 현재 Date type만의 수정을 원한다면, service단에서의 조정이 맞다는 판단이 들었다.
때문에 다음과 같이 service단에서 코드를 재귀함수(무한대댓글을 구현하기 위해)로 추가하며,
원하는 결과를 가져올 수 있도록 조정한다.