글 순서가 반대로 되었다. 이왕 Sequelize ORM에 대해 정리할 것이라면 개발 순서에 따라 모델링부터 작성했으면 보기 좋았을 것 같다. 이번 글은 Sequelize로 테이블을 정의하는 방법(모델링)에 대해 알아보자
Definition
데이터베이스 테이블을 정의하기 위해서는 define()
함수를 사용한다.
module.exports = function(sequelize, DataTypes) {
// define() 함수로 테이블을 정의한다
var User = sequelize.define('User', {
name: DataTypes.String,
birthday: type: DataTypes.DATEONLY,
userType: {
DataTypes.ENUM('user', 'admin'),
defaultValue: 'user'
}
};
첫번째 파라메터 'User'
가 테이블 이름인데 기본적으로 복수형 이름을 갖는 테이블이 생성된다. 이 경우 Users 테이블이 생성된다. 두번째 파라메터가 테이블 컬럼을 정의하는 객체다. 여기서 키(key)는 컬럼명, 값(value)은 컬럼 속성을 정의하는데 DataTypes
에 정의된 데이터 타입을 사용한다.
Getter, Setter
DataTypes에 정의된 속성 말고 좀 더 구체적인 속성을 지정하고 싶다면 get
/set
키를 사용할 수 있다. get
에 함수를 정의하여 테이블에서 컬럼 값을 가져올 때 뭔가 후속 작업을 할 수 있도록 한다. 반대로 set
에 정의한 함수는 테이블에 해당 컬럼 값이 입력될때 전처리 작업을 처리할 수 있다. 비밀번호를 처리는 부분을 예로 들 수 있겠다.
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
password: {
DataTypes.STRING
// 데이터 입력시 전처리
set: function (val) {
this.setDataValue('password', require('crypto').createHash('md5').update(val).digest('hex'))
},
// 데이터 조회시 후처리
get: function () {
return null;
},
}
};
비밀번호를 받아 저장할 경우 Setter를 통해 암호화 하여 저장하고 비밀번호를 조회할 때는 Getter 함수에서 null을 반환하여 숨김처리를 할 수 있다.
Validator
REST API를 구현한다면 POST Body에 대한 검증시 Sequelize의 도움을 받을 수 있다. 이메일 주소를 입력받아 User 테이블에 넣는 상황을 생각해 보자. req.body.email로 요청값을 얻을 수 있다. RegExp 객체로 입력 문자열을 검증한 뒤 그 결과에 따라 작업을 진행할 수 있을 것이다.
function(req, res) {
// 이메일 문자열 체크. 아래 정규표현식은 테스트용 임.
if (!/^account@email.com$/.test(req.body.email)) {
return res.status(400).json({warn: 'check the email pattern'});
}
// 다음 작업: 데이터베이스 저장
// ...
}
만약 Sequelize로 모델링 할때 validate 키를 사용하면 좀 더 간단한 코드를 만들 수 있다.
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
email: {
DataTypes.STRING
validate: {
isEmail: true // 이메일 주소 형식을 검증한다
}
}
};
email 컬럼의 validate 키를 추가하고 {isEmail: true}
객체를 추가했다. 이 모델을 이용해 데이터를 입력하면 Sequelize에서 입력값에 대한 이메일 주소 패턴을 검증한다. 만약 검증에 통과하지 못하면 Sequelize는 데이터입력을 하지않고 에러를 반환하도록 되어있다.
function(req, res) {
// 정의한 User 모델로 데이터를 추가한다
models.User.create({
email: req.body.email
}).then(function (result) {
// 입력에 성공함
res.status(201).json(result);
}).catch(function (err) {
// 이메일 검증 실패인 경우
if (err.name === 'SequelizeValidationError') {
return res.status(400).json({warn: 'check the email pattern'});
}
// 그 외의 서버측 에러 경우
res.status(500).json({error: err});
});
}
Unique
컬럼에 유니크 속성을 추가할 경우 unique
키를 추가한다.
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
birth: {
type: DataTypes.DATEONLY,
unique: true // birth 컬럼값이 유일해야 한다
}
}
};
만약 두 컬럼을 조합하여 유일성을 보장해야 한다면 어떻게 할까? 불리언 값이 아니라 문자열을 설정하면 된다. 예를들어 생일(birth)과 이름(name)을 조합한 값이 유일해야 된다면 우리는 이렇게 코딩할 수 있다.
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
birth: {
type: DataTypes.DATEONLY,
unique: 'userBirthAndNameUnique' // 문자열로 유니크를 지정한다.
},
name: {
type: DataTypes.STRING,
unique: 'userBirthAndNameUnique' // 문자열로 유니크를 지정한다.
}
}
};
실제 테이블 정의에는 이러한 정보를 확인할 수 없고, User 모델로 데이터를 입력하면 Sequelize 단에서 유니크 검증을 처리한다. 중복값을 입력할 경우 validate와 마찬가지로 에러를 반환한다.