Sequelize + Typescript ตอนที่ 1
Tags: typescript, sequelize
Published: 2020-04-05 16:09:45

พวกเราใช้ JavaScript กันอย่างมีความสุขตลอดมา อยู่ๆ ก็มีน้องคนนึงถามขึ้นมาว่า "พี่ๆ เราไม่ใช้ TypeScript เหรอ" จากนั้นก็แลกเปลี่ยนความคิดกันไปมา สรุปได้ว่าเราจะเปลี่ยนไปใช้ TypeScript กัน อะไรคือเหตุผลค่อยว่ากันเนอะ สรุปว่าตอนนี้จะใช้ก็แล้วกัน

เท่าที่กลับไปดูอย่างอื่นก็มีวิธีที่จะทำเป็น TypeScript เกือบหมดแล้ว จะมีก็แต่ ORM ที่เราเลือกใช้ Sequelize (v. 5) ที่ยังดูเหมือนไม่ค่อยชัดเจนกับเรื่องนี้เท่าไหร่ ถึงขั้นเราจะเลิกใช้ Sequelize หนีไป [TypeORM](https://typeorm.io) กันเลยที่เดียว แต่พอไปลองจริงๆ [TypeORM](https://typeorm.io) ยังมีหลายอย่างที่เราคิดว่ายังไม่สมบูรณ์เหมือนกับ Sequelize สุดท้ายก็กลับมาตายรังที่ Sequelize และก็ยังตัดสินใจไม่ใช้ [sequelize-typescript](https://github.com/RobinBuschmann/sequelize-typescript) อีกด้วย เอาจริงๆ วิธีการก็ไม่ต่างจากเดิมเท่าไหร่แค่เปลี่ยนอะไรนิดๆ หน่อยๆ และนี่คือวิธีการใช้ Sequelize กับ TypeScript ที่ทีมเราใช้กันอยู่ตอนนี้

## เครื่องมือเครื่องใช้

ก่อนหน้านี้ใช้ babel มาตลอด หลังจากเปลี่ยนมาใช้ TypeScript ก็เปลี่ยนมาใช้ ts-node เป็นตัวช่วย ก็รู้ว่าง่ายกว่า babel มาก สามารถใช้ร่วมกับ JavaScript ปกติได้เลย ใครที่ config อะไรแปลกๆ ใน babel ก็ลอง test กันดูก่อนนะ ส่วน dependencies ที่ต้องใช้เพิ่มเติมจาก Sequelize ก็คือ
* @types/node
* @types/validator
* @types/bluebird

## สร้าง Connection

ในบทความนี้ขอใช้ database เป็น sqlite เผื่อใครจะ clone code ไปทำตามจะได้ลุยกันได้เลย ตามจริงจะใช้ตัวไหนก็ไม่ต่างกันเพราะเราใช้ ORM แล้วนิเนอะ แล้วก็สร้าง connection เหมือนที่เราเคยสร้างตามปกติ

```typescript
import { Sequelize } from 'sequelize';

export const sequelize = new Sequelize({
  dialect: 'sqlite',
  storage: './src/database/demo.db',
});
```

## สร้าง Model หรือ Table นั่นแหละ

ใครที่เคยสร้าง Model แบบ sequelize.define ก็เปลี่ยนมาใช้ class extends Model มันง่ายกว่าเยอะมาก สร้าง class กำหนด type แล้วใช้ Sequelize init เพื่อสร้าง Sequelize Model เท่านี้ Model ก็พร้อมใช้งานแล้ว ขอสร้างไว้ 3 Model ไว้ทำ association ในตอนต่อไปละกันเนอะ

```typescript
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../database/connection';

export class Actor extends Model {
  id!: number;

  firstName!: string;

  lastName!: string;

  createdAt!: Date;

  UpdatedAt!: Date;
}

Actor.init(
  {
    firstName: {
      type: DataTypes.STRING,
      allowNull: false,
    },

    lastName: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  },
  {
    sequelize,
    tableName: 'actor',
    freezeTableName: true,
  },
);
```

```typescript
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../database/connection';

export class Movie extends Model {
  id!: number;

  title!: string;

  year!: number;

  createdAt!: Date;

  UpdatedAt!: Date;
}

Movie.init(
  {
    title: {
      type: DataTypes.STRING,
      allowNull: false,
    },

    year: {
      type: DataTypes.INTEGER,
      allowNull: false,
    },
  },
  {
    sequelize,
    tableName: 'movie',
    freezeTableName: true,
  },
);
```

```typescript
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../database/connection';

export class Genre extends Model {
  id!: number;

  name!: string;

  createdAt!: Date;

  UpdatedAt!: Date;
}

Genre.init(
  {
    name: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  },
  {
    sequelize,
    tableName: 'genre',
    freezeTableName: true,
  },
);
```

## ทดสอบ Connection

เมื่อได้ Connection กับ Model แล้วก็มาลองทดสอบกันหน่อย ปกติเราสามารถเรียก class ที่เราสร้างเพื่อทดสอบ Connection ได้เลย แต่ถ้ามีหลายๆ Model เราควรให้ทุก Model init ให้เรียบร้อยก่อน จึงสร้าง file รวมขึ้นมาเพื่อ init ทุก Model ซึ่งวิธีนี้จะช่วยแก้ปัญหาการทำ associations ซึ่งจะกล่าวถึงในตอนต่อไป

```typescript
import './Actor';
import './Movie';
import './Genre'
```

จากนั้นก็สามารถเรียก sequelize.authenticate() เพื่อทดสอบ Connection ได้ตามปกติและสามารถทดสอบการ Query จาก Model ได้เลย จะเห็นว่าแต่ละ Model จะมี type ติดมาด้วยแล้ว

```typescript
import './models';
import { sequelize } from './database/connection';
import { Actor } from './models/Actor';

(async () => {
  try {
    await sequelize.authenticate();
    console.log('Connection has been established successfully.');

    // Find all actors
    const actors = await Actor.findAll();

    console.log(actors);
  } catch (err) {
    console.error('Unable to connect to the database:', err);
  }
})();
```

## สรุป

หลังจากทำตามขึ้นตอนด้านบนเราก็จะมี Model พร้อมใช้งาน โดยสามารถใช้งานได้ตามปกติไม่ต่างจากที่ทำใน JavaScript เลย เพียงแต่จะมี type ติดไปด้วย แต่ยังมีอีกส่วนนึงที่ต่างไปจากตอนใช้ JavaScript ก็คือการทำ association พวก One-to-Many, Many-to-Many นั่นแหละ ไว้เจอกันใหม่ตอนหน้าครับ

{% github pthongtaem/sequelize-typescript-demo %}