시퀄라이즈 모델 생성
시퀄라이즈는 promise 기반 Node.js ORM 이다. Postgres,MySQL,MariaDB,SQLite 등 다양한 SQL 서버와 호환된다. 데이터 베이스 트랜잭션(Transaction), 관계(relation), 지연 로딩(lazy loading), 레플리케이션(Replication) 등을 지원한다.
시퀄라이즈는 Semantic Versioning 을 따르며 v10 버전 이상의 노드에서 호환된다.
Quick example
공식문서에서 명시한 기본 사용법은 아래와 같다.
const { Sequelize, Model, DataTypes } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory:');
class User extends Model {}
User.init({
username: DataTypes.STRING,
birthday: DataTypes.DATE
}, { sequelize, modelName: 'user' });
(async () => {
await sequelize.sync();
const jane = await User.create({
username: 'janedoe',
birthday: new Date(1980, 6, 20)
});
console.log(jane.toJSON());
})();
트랜잭션이란?
트랜잭션(Transaction 이하 트랜잭션)이란, 데이터베이스의 상태를 변화시키기 해서 수행하는 작업의 단위를 뜻한다. 간단하게 말하면 SQL을 이용해 데이터베이스를 접근 하는 것을 의미한다.SELECT INSERT DELETE UPDATE
추가로 공식문서의 API Reference 를 참고해 보면 좋을 것 같다.
Model
이란?
Models 는 시퀄라이즈에서 필수적이다. 모델은 데이터베이스의 테이블에 해당하는 추상적인 개념이다. 시퀄라이즈에서 모델은 Model
을 extends
하는 클래스(class)다.
모델은 시퀄라이즈가 데이터베이스의 테이블이름,테이블에서 어떤 컬럼이 있는지, 컬럼의 데이터 타입은 무엇인지와 같은 엔티티(entity) 를 인식하도록 해준다.
시퀄라이즈에서 모델은 이름을 가진다. 이 이름은 데이터베이스의 테이블 이름과 일치하지 않아도 된다. 대체로 시퀄라이즈의 모델은 User
와 같은 단수 이름을 가지고, 테이블은 Users
와 같은 복수 이름을 가진다.
Model
정의
참고
시퀄라이즈는 id 를 자동으로 넣어주기 때문에 아래를 생략 가능하다.
...
id : {
type : DataTypes.INTEGER,
primaryKey : true,
autoIncrement : true
}
...
참고
시퀄라이즈는 id 를 자동으로 넣어주기 때문에 아래를 생략 가능하다.
...
id : {
type : DataTypes.INTEGER,
primaryKey : true,
autoIncrement : true
}
...
시퀄라이즈에서 모델은 아래 두 가지 방법으로 정의될 수 있다.
Calling sequelize.define(modelName, attributes, options)
Extending Model and calling init(attributes, options)
모델이 정의된 후, sequelize.models
에서 모델 이름을 통해 접근 가능하다.
에제를 통해 배우기 위해, user
를 나타내는 firstName
과 lastName
을 가진 모델을 생성해보자. 모델 이름은 User
이고 데이터베이스 테이블에서 나타내는 이름은 Users
다.
아래에서 두 가지 방법으로 모델을 정의했다. 모델이 정의된 후 sequelize.models.User
로 모델에 접근 가능하다.
Using sequelize.define
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory:');
const User = sequelize.define('User', {
// Model attributes are defined here
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING
// allowNull defaults to true
}
}, {
// Other model options go here
});
// `sequelize.define` also returns the model
console.log(User === sequelize.models.User); // true
Extending Model
const { Sequelize, DataTypes, Model } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory');
class User extends Model {}
User.init({
// Model attributes are defined here
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING
// allowNull defaults to true
}
}, {
// Other model options go here
sequelize, // We need to pass the connection instance
modelName: 'User' // We need to choose the model name
});
// the defined model is the class itself
console.log(User === sequelize.models.User); // true
내부적으로 sequelize.define
은 Model.init
으로 불린다. 따라서 두 방법은 근본적으로 동일하다.
Table name inference
위 두 방법을 보면, 데이터베이스 테이블 이름인 Users
는 정의되지 않은 반면, 시퀄라이즈 모델 이름인 User
는 주어졌다.
기본적으로 테이블 이름이 주어지지 않으면, 시퀄라이즈는 자동적으로 모델이름의 복수형을 테이블 이름으로 생성한다.
Enforcing the table name to be equal to the model name
freezeTableName: true
옵션을 줌으로써 위와 같이 테이블 이름이 자동으로 생성되는것을 멈출 수 있다. 이 옵션을 주면 복수형을 붙이지 않고 테이블 이름을 모델 이름과 같게 설정한다.
sequelize.define('User', {
// ... (attributes)
}, {
freezeTableName: true
});
위 예제는 테이블 이름과 모델 이름 모두 User
로 생성한다.
이 과정을 시퀄라이즈 인스턴스에 대해 전역적으로 설정하려면 아래와 같이한다.
...
const sequelize = new Sequelize('sqlite::memory:', {
define: {
freezeTableName: true
}
});
...
이렇게 설정하면 모든 테이블이름이 모델 이름과 같게 설정된다.
Providing the table name directly
아래와 같은 방법으로 테이블 이름을 직접적으로 설정할 수 있다.
sequelize.define('User', {
// ... (attributes)
}, {
tableName: 'Employees'
});
Model synchronization
모델을 정의하는 것은 데이터베이스의 테이블에 대한 정보를 시퀄라이즈에게 전송하는 것이다.
하지만 만약 데이터베이스가 실제로 존재하지 않거나, 존재하지만 모델과 다른 컬럼을 가지는 등 차이가 있다면 어떨까?
이것이 바로 모델 동기화가 필요한 이유다. 모델은 model.sync(options)
라고 불리는 Promise 를 반환하는 비동기 함수에 의해 데이터베이스와 동기화될 수 있다. 이 함수가 실행되면 시퀄라이즈는 자동적으로 데이터베이스에 SQL
쿼리를 실행한다.
자바스크립트로 작성된 모델이 아닌 데이터베이스 테이블에서 일어난다는 것을 주목하자.
User.sync() : 테이블이 존재하지 않는다면 생성한다. 만약 테이블이 존재한다면 실행되지 않는다.
User.sync({ force: true }) : 테이블을 생성한다. 만약 테이블이 이미 존재한다면 기존에 있던 테이블을 삭제하고 새로 생성한다.
User.sync({ alter: true }) : 테이블에 어떤 컬럼이 있는지, 데이터 타입은 무엇인지 데이터베이스에 있는 테이블의 현재 상태를 체크한다. 그리고 시퀄라이즈 모델과 동기화 하기 위한 필수적인 변환 작업을 실행한다.
예를들어 아래와 같이 사용할 수 있다.
await User.sync({ force: true });
console.log("The table for the User model was just (re)created!");
Synchronizing all models at once
sequelize.sync()
를 이용해 자동적으로 모든 모델을 동기화할 수 있다.
await sequelize.sync({ force: true });
console.log("All models were synchronized successfully.");
Dropping tables
특정 모델과 관계된 테이블을 삭제한다.
await User.drop();
console.log("User table dropped!");
모든 테이블을 삭제한다.
await sequelize.drop();
console.log("All tables dropped!");
Database safety check
sync
와 drop
명령은 잘못 실행했을 시 리스크가 크기 때문에. 시퀄라이즈는 정규표현식을 이용한 match
옵션을 사용해 추가적인 안전 체크를 할 수 있도록 제공한다.
// This will run .sync() only if database name ends with '_test'
sequelize.sync({ force: true, match: /_test$/ });
Synchronization in production
위 설명에 나와있듯이 sync({ force: true })
와 sync({ alter: true })
옵션은 파괴적인 명령이다. 따라서 배포시에는 사용하지 않는것을 권장한다.
위 두 명령어 대신, 동기화(synchronization)는 시퀄라이즈 CLI 의 도움을 받아 향상된 마이그레이션(Migration) 개념으로 실행되어야 한다.
Timestamps
기본적으로 시퀄라이즈는 DataTypes.DATE
타입을 사용하는 createdAt
과 updatedAt
필드를 모든 모델에 추가한다. 시퀄라이즈를 이용해 생성 또는 업데이트하면 이 필드들이 자동적으로 설정된다. createdAt
필드는 생성된 시점에 대한 정보를 나타내는 타임스탬프를 포함하고 있고 updatedAt
필드는 마지막 업데이트에 대한 타임스탬프를 포함한다.
참고
이 작업은 Secretalize 에서 실행된다.(즉, SQL 트리거로는 수행되지 않음). 즉, 직접 SQL 쿼리(예: 다른 방법을 통해 Secretize 없이 수행된 쿼리)가 이러한 필드를 자동으로 업데이트하지 않는다.
timestamps: false
옵션을 통해 자동적으로 타임스탬프 필드가 설정되지 않도록 할 수 있다.
sequelize.define('User', {
// ... (attributes)
}, {
timestamps: false
});
또한 createdAt/updatedAt
중 하나의 옵션만 설정하는 것이 가능하고 생성되는 컬럼에 이름을 변경할 수도 있다.
class Foo extends Model {}
Foo.init({ /* attributes */ }, {
sequelize,
// don't forget to enable timestamps!
timestamps: true,
// I don't want createdAt
createdAt: false,
// I want updatedAt to actually be called updateTimestamp
updatedAt: 'updateTimestamp'
});
Column declaration shorthand syntax
만약 컬럼을 특정짓는게 데이터타입밖에 없다면 아래와 같이 축약형으로 사용가능하다.
// This:
sequelize.define('User', {
name: {
type: DataTypes.STRING
}
});
// Can be simplified to:
sequelize.define('User', { name: DataTypes.STRING });
Default Values
기본적으로 시퀄라이즈는 컬럼의 기본값을 Null
로 추정한다. 이러한 설정은 컬럼 정의에 defaultValue
인자를 추가해 변경할 수 있다.
sequelize.define('User', {
name: {
type: DataTypes.STRING,
defaultValue: "John Doe"
}
});
Sequelize.NOW
같은 몇몇 특정한 값들도 기본값으로 설정 가능하다.
sequelize.define('Foo', {
bar: {
type: DataTypes.DATETIME,
defaultValue: Sequelize.NOW
// This way, the current date/time will be used to populate this column (at the moment of insertion)
}
});
Data Types
정의한 모든 컬럼은 반드시 데이터타입을 가져야 한다. 시퀄라이즈는 많은 빌트인 데이터타입들을 제공한다. 아래와같이 import
해 사용한다.
const { DataTypes } = require("sequelize"); // Import the built-in data types
Strings
DataTypes.STRING // VARCHAR(255)
DataTypes.STRING(1234) // VARCHAR(1234)
DataTypes.STRING.BINARY // VARCHAR BINARY
DataTypes.TEXT // TEXT
DataTypes.TEXT('tiny') // TINYTEXT
DataTypes.CITEXT // CITEXT PostgreSQL and SQLite only.
Boolean
DataTypes.BOOLEAN // TINYINT(1)
Numbers
DataTypes.INTEGER // INTEGER
DataTypes.BIGINT // BIGINT
DataTypes.BIGINT(11) // BIGINT(11)
DataTypes.FLOAT // FLOAT
DataTypes.FLOAT(11) // FLOAT(11)
DataTypes.FLOAT(11, 10) // FLOAT(11,10)
DataTypes.REAL // REAL PostgreSQL only.
DataTypes.REAL(11) // REAL(11) PostgreSQL only.
DataTypes.REAL(11, 12) // REAL(11,12) PostgreSQL only.
DataTypes.DOUBLE // DOUBLE
DataTypes.DOUBLE(11) // DOUBLE(11)
DataTypes.DOUBLE(11, 10) // DOUBLE(11,10)
DataTypes.DECIMAL // DECIMAL
DataTypes.DECIMAL(10, 2) // DECIMAL(10,2)
Unsigned & Zerofill integers - MySQL/MariaDB only
MySQL 과 MariaDB 에서, INTEGER, BIGINT, FLOAT, DOUBLE
데이터타입은 아래와같이 UNSIGNED 혹은 ZEROFILL 로 할당될 수 있다.
DataTypes.INTEGER.UNSIGNED
DataTypes.INTEGER.ZEROFILL
DataTypes.INTEGER.UNSIGNED.ZEROFILL
// You can also specify the size i.e. INTEGER(10) instead of simply INTEGER
// Same for BIGINT, FLOAT and DOUBLE
Dates
DataTypes.DATE // DATETIME for mysql / sqlite, TIMESTAMP WITH TIME ZONE for postgres
DataTypes.DATE(6) // DATETIME(6) for mysql 5.6.4+. Fractional seconds support with up to 6 digits of precision
DataTypes.DATEONLY // DATE without time
UUID
DataTypes.UUID
은 PostgreSQL 과 SQLite 의 UUID
, MySQL 의 CHAR(36)
데이터타입이 됩니다. 시퀄라이즈는 Sequelize.UUIDV1
또는 Sequelize.UUIDV4
를 사용해 필드들의 UUID 들을 자동적으로 생성할 수 있다.
{
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4 // Or Sequelize.UUIDV1
}
Column Options
컬럼을 정의할 때, 컬럼의 타입을 특정하는것과 allowNull
,defaultValue
를 제외하고도
사용할 수 있는 많은 옵션들이 있다.
const { Model, DataTypes, Deferrable } = require("sequelize");
class Foo extends Model {}
Foo.init({
// instantiating will automatically set the flag to true if not set
flag: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true },
// default values for dates => current time
myDate: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
// setting allowNull to false will add NOT NULL to the column, which means an error will be
// thrown from the DB when the query is executed if the column is null. If you want to check that a value
// is not null before querying the DB, look at the validations section below.
title: { type: DataTypes.STRING, allowNull: false },
// Creating two objects with the same value will throw an error. The unique property can be either a
// boolean, or a string. If you provide the same string for multiple columns, they will form a
// composite unique key.
uniqueOne: { type: DataTypes.STRING, unique: 'compositeIndex' },
uniqueTwo: { type: DataTypes.INTEGER, unique: 'compositeIndex' },
// The unique property is simply a shorthand to create a unique constraint.
someUnique: { type: DataTypes.STRING, unique: true },
// Go on reading for further information about primary keys
identifier: { type: DataTypes.STRING, primaryKey: true },
// autoIncrement can be used to create auto_incrementing integer columns
incrementMe: { type: DataTypes.INTEGER, autoIncrement: true },
// You can specify a custom column name via the 'field' attribute:
fieldWithUnderscores: { type: DataTypes.STRING, field: 'field_with_underscores' },
// It is possible to create foreign keys:
bar_id: {
type: DataTypes.INTEGER,
references: {
// This is a reference to another model
model: Bar,
// This is the column name of the referenced model
key: 'id',
// With PostgreSQL, it is optionally possible to declare when to check the foreign key constraint, passing the Deferrable type.
deferrable: Deferrable.INITIALLY_IMMEDIATE
// Options:
// - `Deferrable.INITIALLY_IMMEDIATE` - Immediately check the foreign key constraints
// - `Deferrable.INITIALLY_DEFERRED` - Defer all foreign key constraint check to the end of a transaction
// - `Deferrable.NOT` - Don't defer the checks at all (default) - This won't allow you to dynamically change the rule in a transaction
}
},
// Comments can only be added to columns in MySQL, MariaDB, PostgreSQL and MSSQL
commentMe: {
type: DataTypes.INTEGER,
comment: 'This is a column name that has a comment'
}
}, {
sequelize,
modelName: 'foo',
// Using `unique: true` in an attribute above is exactly the same as creating the index in the model's options:
indexes: [{ unique: true, fields: ['someUnique'] }]
});
Taking advantage of Models being classes
시퀄라이즈의 모델은 ES6 클래스이므로, 별도로 인스턴스를 추가하거나 클래스메소드를 추가할 수 있다.
class User extends Model {
static classLevelMethod() {
return 'foo';
}
instanceLevelMethod() {
return 'bar';
}
getFullname() {
return [this.firstname, this.lastname].join(' ');
}
}
User.init({
firstname: Sequelize.TEXT,
lastname: Sequelize.TEXT
}, { sequelize });
console.log(User.classLevelMethod()); // 'foo'
const user = User.build({ firstname: 'Jane', lastname: 'Doe' });
console.log(user.instanceLevelMethod()); // 'bar'
console.log(user.getFullname()); // 'Jane Doe'
컬럼 관련 찾아볼만한 링크
https://jeonghwan-kim.github.io/node/2017/02/06/utf8mb4-in-sequelize.html
Author And Source
이 문제에 관하여(시퀄라이즈 모델 생성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@ywoosang/시퀄라이즈-모델-생성저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)