MySQL 반환값은 배열로만?

00_8_3·2022년 2월 12일
0

SEEME 이슈

목록 보기
3/10

ORM을 사용하지 않고

그 동안 여러 프로젝트를 진행하면서 mongoose라던가 TypeORM 같은 ORM을 사용 하였다.
이러하다 보니 뭔가 도구를 사용하기 위한 도구를 공부하는 느낌이라,
이참에 ORM을 사용하지 않고 진행하기로 하였다!

MySQL 8버전으로 mysql2 드라이버를 사용하였다.

마주친 문제

대부분의 ORM들은 스키마를 정의하면 findOne이라던가 find 또는 findById같은 함수를 제공한다.

하지만 mysql2의 쿼리로 위와 같은 함수의 반환값을 받으려 한다면 어떨가?

SELECT * FROM users WHERE id = 1; // 1
또는
SELECT * FROM posts WHERE user_id = 1; // 2

1번 같은 경우 user.id === 1인 user 객체 하나가 반환될 것이라 생각 할 것이다.

예상 결과

{
	"id": 1,
    "email": "test@gmail.com",
}

하지만 안타깝게도 결과는 배열을 내뱉는다.
실제 결과

[
  {
	"id": 1,
    "email": "test@gmail.com",
  }
]

LIMIT 1을 넣어줘도 결과는 배열이다~

왜 이런 결과가 나올까?

답은 생각보다 간단하다. mysql2 라이브러리가 배열만 내놓기 때문이다.
라이브러리를 들여다 보면


// 오버로딩하는 함수 4개 중, 내가 사용하는 하나이다.
query<T extends RowDataPacket[][] | RowDataPacket[] | OkPacket | OkPacket[] | ResultSetHeader>(
    sql: string,
    values: any | any[] | { [param: string]: any }
  ): Promise<[T, FieldPacket[]]>;

제네릭 T가 상속받는 것 들을 알 수있는데,
SELECT 같은 경우 RowDataPacket 타입으로 받아 오게 되어있다.
보면은 반환값이 RowDataPacket[][] 또는 RowDataPacket[]이기 때문에
SELECT로 1개의 값을 찾아도 배열로 반환 하는 것이다.

그럼 어떻게 해야하나?

안타깝게도 findOne과 같은 객체 하나만을 반환하는 기능을 구현하기 위해서는

// 반환값의 두 번째 인자는 FieldPacket으로 나에겐 필요 없기 때문에 무시한다.
findUser(id: number) {
	const [rows, _] = mysql.query(`SELECT * FROM users WHERE id = ?`, [id]) ;

	return rows[0];
}
  • 위 와 같은 방식으로 값을 꺼내 오는 findOne 함수를 따로 구현하거나

  • ORM을 사용하여 라이브러리가 제공하는 함수를 사용하는 수 밖에 없다.

추가 2022-05-04

class-transformerplainToInstance을 이용한 객체화.
select에서 원하는 column을 findUserDto에 명시 해주면 된다.

//return rows[0]

return plainToInstance(findUserDto, rows[0])// 첫 번째 인자에 변환해주고싶은 Class 주입

마침

ORM 에서는 getOne과 같은 편의 기능이 제공되나 생 쿼리로만 구현을 하니 이와 같은 부분을 직접 다 구현해야 했다.
SQL 사용에 능숙해져 가는 느낌에 좋았지만 그래도 코드의 관리 힘들기 때문에 ORM을 사용 할 것 같다.

프로젝트를 진행하면서 겪었던 이슈들을 정리하지 않는 나의 게으름을 반성하며 작성하였습니다~

0개의 댓글