0. 개발환경
@nestjs/typeorm : 10.0.0
nest : 10.1.18
mysql 8.0.xx
typescript : 5.1.x
1. 문제의 발생
@Entity('user')
export class UserEntity extends CoreEntity {
...
@Column({
type: 'enum',
enum: Role,
array: true,
default: [Role.User],
})
@IsString()
public roles!: Role[];
...
}
user.entity를 설계하는 과정에서 Role을 Enum array로 관리하고자 하였고, 코드상으로는 syntax적 문제가 없었다.
그런데 막상 npm run start:dev를 실행하여 mysql 서버상에 table 생성을 시도하자 아래와 같은 에러가 발생했다.
query failed: ALTER TABLE `user` ADD `roles` enum array ('User', 'Admin') NOT NULL DEFAULT 'User'
error:
Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'array ('User', 'Admin') NOT NULL DEFAULT 'User'' at line 1
2. 문제의 원인
혼자 헤매다가 github에서 원인을 찾을 수 있었다.
바로 MySQL에서는 array type을 쓸 수 없다는 점... Postgres에서는 지원하는데, MySQL에서는 지원하지 않는다고 한다.
사실 Array를 쓸 상황이면 정규화를 해줘야하는 상황이 온거라고 보는 듯하다.
아래 링크에서 해당 이유를 찾을 수 있다.
database schema - How to store arrays in MySQL? - Stack Overflow
3. 문제의 해결
나에게 남겨진 선택지는
1. RDBMS 자체를 바꿔버린다.
2. Role 테이블을 분리하고 User와 N:M으로 Join한다.
3. user-role 테이블을 생성하고 User와 N:1으로 Join한다. 이때 Role의 enum 값들은 코드상에 하드코딩한다.
4. string type으로 저장하고 불러올 때 split 해오는 Transform을 주입한다.
5. 아예 object화 시켜서 json 타입으로 저장해버린다.
정도가 있을 것 같다.
여기저기 물어보고 찾아보면서 고민해본 결과 Role을 확장성 있게 관리하고, 코딩 법칙들을 최대한 지키면서 구현하기 위해 2번( Role 테이블을 분리하고 User와 N:M으로 Join한다.)을 선택했다.
단, N:M으로 생성되는 user-role 테이블에 관해서는 조회시 성능을 잘 생각해서 코딩해야할 것 같다.
위의 ERD와 같은 구조로 생성할 수 있었다.
4. 참고문서
- typescript - How to add an enum array in a TypeOrm entity? - Stack Overflow
- Nestjs typeorm mydsql enum types with array dont work · Issue #10363 · typeorm/typeorm (github.com)
- database schema - How to store arrays in MySQL? - Stack Overflow