Sequelize
는 TypeScript와 Node.js에서 ORM(Object Relation Mapping)
을 사용하게 해주는 라이브러리이다.
자바스크립트의 객체와 관계형 데이터베이스를 서로 연결해주어 DB작업을 더 쉽게 할 수 있도록 도와준다.
sequelize와 sequelize를 편하게 사용하게 해주는 명렁어 라이브러리인 sequelize-cli, MySQL 서버와 연결해주는 mysql2를 설치해줍니다.
npm install sequelize sequelize-cli mysql2
설치가 완료되면 sequlize init
을 실행합니다.
(저는 글로벌 설치를 사용해서 명령어를 바로 사용했습니다. local에서 사용하려면 npx sequelize-cli init을 사용하시면 될거 같습니다.)
실행을 완료하면 다음과 같은 2개의 파일과 4개의 폴더가 생성됩니다.
config/cofing.json
models/index.js
migrations/
seeders/
sequelize db:create
명령어를 실행하면 config에 있는 DB 스키마의 이름으로 생성된다.
sequelize db:migrate
migrations
폴더 안에 이름에 create가 포함된 js파일이 있으면 그것에 맞추어 테이블을 생성해준다.
history
테이블이 user
테이블의 user_no
를 외래키로 가지는 테이블을 구성하려고 한다. 그래서 user
테이블을 먼저 만들기 위해 이름에 1을 붙여줬다.
// 1.create.user.js
"use strict";
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable(
"users",
{
no: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
id: {
type: Sequelize.STRING,
allowNull: false,
},
password: {
type: Sequelize.STRING,
allowNull: false,
},
username: {
type: Sequelize.STRING,
allowNull: false,
},
deleted: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.fn('NOW'),
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.fn('NOW'),
},
},
{
timestamps: true,
initialAutoIncrement: 0
}
);
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable("users");
},
};
// 2.create.history.js
"use strict";
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface
.createTable(
"history",
{
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
input: {
type: Sequelize.STRING,
allowNull: false,
},
output: {
type: Sequelize.STRING,
allowNull: false,
},
deleted: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.fn("NOW"),
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.fn("NOW"),
},
},
{
timestamps: true,
}
)
.then(async () => {
await queryInterface.addColumn("history", "user_no", {
type: Sequelize.INTEGER,
});
await queryInterface.addConstraint("history", {
fields: ["user_no"],
type: "foreign key",
name: "users_history_no_fk",
references: {
table: "users",
field: "no"
},
onDelete: "cascade",
onUpdate: "cascade",
});
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable("history");
},
};
외래키를 설정해주기 위해서는 모든 테이블이 완성된 후에 queryInterface
를 사용하여 외래키로 사용할 column을 만들어주고 constraint을 추가하여 만들어줘야한다.
그 부분이 2.history.create.js의 아래쪽에 있는 .then()부분에 작성되어있다.
// 2.history.create.js의 아래부분
// ...
.then(async () => {
await queryInterface.addColumn("history", "user_no", {
type: Sequelize.INTEGER,
});
await queryInterface.addConstraint("history", {
fields: ["user_no"],
type: "foreign key",
name: "users_history_no_fk",
references: {
table: "users",
field: "no"
},
onDelete: "cascade",
onUpdate: "cascade",
});
});
// ...
.then()
은 알고있듯이 비동기를 위한 js의 promise의 실행이 된 후에 호출되는 함수이다.
테이블이 완성된 후에 queryInterface
로 user_no
라는 column
을 추가한다.
그 이후 addConstraint
를 호출하여 history
테이블에 있는 user_no
에 users_history_no_fk
라는 이름의 users
테이블의 no
값을 부모로 하는 foreign key를 생성한다.
models
폴더 안에 원하는 이름의 js파일을 생성하면 된다.
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define(
"user",
{
no: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
id: {
type: DataTypes.STRING,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
username: {
type: DataTypes.STRING,
allowNull: false,
},
deleted: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
},
{
sequelize,
tableName: "users",
timestamps: true,
}
);
user.associate = (models) => {
user.hasMany(models.history, {
foreignKey: "user_no",
onDelete: "cascade",
allowNull: "false",
});
};
return user;
};
DataTypes
에 있는 타입들을 가지고 DB에 저장될 타입을 설정한다. allowNull
을 줘서 NotNull
을 설정 할 수 있다.timestamps
을 설정하면 자동으로 created-date
와 updated-date
를 관리해준다.associate를 이용하여 관계에 대한 정보를 추가해줘야 모델에 오류없이 사용할 수 있다.
일대다 관계에서는 hasMany
와 belongsTo
를 사용하여 연결한다.
module.exports = (sequelize, DataTypes) => {
const history = sequelize.define(
"history",
{
input: {
type: DataTypes.STRING,
allowNull: false,
},
output: {
type: DataTypes.STRING,
allowNull: false,
},
deleted: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
},
{
sequelize,
tableName: "history",
timestamps: true,
}
);
history.associate = (models) => {
history.belongsTo(models.user, {
foreignKey: "user_no",
})
}
return history;
};
DB 테이블을 구성할때 주의할 점이 있는데 sequelize는 각 테이블마다 id값을 필수로 요구한다.
그래서 설계를 할때 id 값을 빼놓지 말아야한다.