타입오알엠 - value.toUpperCase is not a function at MysqlDriver.normalizeDatetimeFunction
부트캠프 마지막 팀 프로젝트를 진행하며, 백엔드 코드를 타입오알엠(TypeORM)을 사용하여 작성하기로 했습니다. 타입오알엠 공식 문서를 참고하여 마리아디비(MariaDB)와 연동하였고, @Entity()를 사용하여 테이블을 생성하려고 했는데 다음과 같은 오류가 발생했습니다.
1
2
3
4
5
6
7
8
9
10
11
TypeError: value.toUpperCase is not a function
at MysqlDriver.normalizeDatetimeFunction (/Users/hyemin/Desktop/hyemin/myMoney/backend/node_modules/typeorm/driver/mysql/MysqlDriver.js:1063:42)
at MysqlDriver.normalizeDefault (/Users/hyemin/Desktop/hyemin/myMoney/backend/node_modules/typeorm/driver/mysql/MysqlDriver.js:647:25)
at TableUtils.createTableColumnOptions (/Users/hyemin/Desktop/hyemin/myMoney/backend/node_modules/typeorm/schema-builder/util/TableUtils.js:18:29)
at /Users/hyemin/Desktop/hyemin/myMoney/backend/node_modules/typeorm/schema-builder/table/Table.js:282:58
at Array.map (<anonymous>)
at Table.create (/Users/hyemin/Desktop/hyemin/myMoney/backend/node_modules/typeorm/schema-builder/table/Table.js:282:18)
at RdbmsSchemaBuilder.createNewTables (/Users/hyemin/Desktop/hyemin/myMoney/backend/node_modules/typeorm/schema-builder/RdbmsSchemaBuilder.js:417:41)
at RdbmsSchemaBuilder.executeSchemaSyncOperationsInProperOrder (/Users/hyemin/Desktop/hyemin/myMoney/backend/node_modules/typeorm/schema-builder/RdbmsSchemaBuilder.js:167:20)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async RdbmsSchemaBuilder.build (/Users/hyemin/Desktop/hyemin/myMoney/backend/node_modules/typeorm/schema-builder/RdbmsSchemaBuilder.js:66:13)
오류 코드가 길긴하지만 요약해보면 “날짜의 기본값을 지정할 때 MYSQL이 이해할 수 있는 SQL 표현식으로 작성해라.”라는 의미입니다.
다음 기능을 구현하기 위해, 날짜형태의 컬럼에 기본 값 설정을 잘못하여 발생한 오류입니다.
- 유저가 신고됨
- 정지가 종료되는 날짜를 테이블에 저장
- 유저가 로그인을 시도할 때 오늘 날짜와 DB에 저장된 정지가 종료되는 날짜를 비교하여 로그인을 막음
정지가 종료되는 날짜 칼럼을 null 또는 undefined로 비워두는 것은 좋지 않다는 생각이 들어, 회원가입하는 유저들의 정지가 종료되는 날짜를 가입하는 날의 하루전으로 설정했다.
위의 내용을 구현하기 위해 new Date
를 사용해서 하루 전을 기본값으로 설정했습니다.
default: () => new Date(Date.now() - 86400000),
전체코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id!: number;
@Column({ comment: "비밀번호" })
password!: string;
@Column({ comment: "이메일", unique: true })
email!: string;
@Column({ comment: "닉네임", unique: true })
nickname!: string;
@Column({
type: "timestamp",
comment: "정지 종료 날짜",
default: () => " default: () => new Date(Date.now() - 86400000)"
})
expired_date!: Date;
@Column({
comment: "관리자, 일반 유저 구분",
default: false
})
isAdmin!: boolean;
@Column({
comment: "신고 횟수",
default: 0
})
report_count!: number;
}
Mysql이 default: () => new Date(Date.now() - 86400000),
이 부분을 이해하지 못해 오류가 발생하고 있었습니다.
MYSQL이 이해할 수 있는 코드로 변경하였더니, 오류가 해결되었고 테이블도 정상적으로 생성되었습니다.
전체 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id!: number;
@Column({ comment: "비밀번호" })
password!: string;
@Column({ comment: "이메일", unique: true })
email!: string;
@Column({ comment: "닉네임", unique: true })
nickname!: string;
@Column({
type: "timestamp",
comment: "정지 종료 날짜",
default: () => "CURRENT_TIMESTAMP"
})
expired_date!: Date;
@Column({
comment: "관리자, 일반 유저 구분",
default: false
})
isAdmin!: boolean;
@Column({
comment: "신고 횟수",
default: 0
})
report_count!: number;
}
테이블 정상적으로 생성
생각해보니, 위의 방법은 하루 전날을 기본 값으로 설정하는 것이 아니라 가입할 때의 시간과 날짜를 기본값으로 설정해주기 때문에 우리 팀이 원했던 것과는 달라 다른 방법을 시도해보았습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
export const joinUser = (req: Request, res: Response) =>{
const { email, password, nickname } = req.body;
const calcExpiredDate = new Date() - 86400000
const user = new User();
user.email = userData.email;
user.password = userData.password;
user.nickname = userData.nickname;
user.expired_date = calcExpiredDate;
await userRepository.save(user);
}
회원가입을 하는 백엔드 코드에서 직접 회원가입 하는 날의 하루 전의 값을 계산해서 데이터베이스에 넣어주는 방법으로 구현했습니다.
위의 코드로 구현하는 것이 가장 베스트인지, 혹은 더 좋은 방법이 있는지 멘토링 시간에 물어보았습니다.
멘토님께서는
- 왜 null 또는 undefined가 들어가면 안되는지
- 회원가입하는 날보다 왜 하루 전이어야 하는지
물어보셨습니다.
답변
- null 또는 undefined가 들어가면 안되는지: 데이터베이스의 칼럼이 비어있는 것이 좋지 않다고 생각했기 때문
- 회원가입하는 날보다 왜 하루 전이어야 하는지: 회원가입한 유저들이 로그인을 하고 서비스를 이용해야하기 때문
멘토링이 종료되고 팀원들과 이야기를 나누며 정지가 종료되는 날이 꼭 하루 전일 필요가 없다는 결론을 내렸고, MySQL의 CURRENT_TIMESTAMP를 사용해서 기본값을 설정하기로 결정했습니다.
프로젝트를 진행하며, “정지가 종료된 날” 컬럼은 결국 사라졌습니다…