DEV Community

Weerasak Chongnguluam
Weerasak Chongnguluam

Posted on • Edited on

Elixir ต่อฐานข้อมูลด้วย Ecto ตอนที่ 2 สร้าง table ด้วย migration script

วันนี้จะลองสร้าง table ผ่าน Ecto Migration กัน

เริ่มแรกเราต้อง config repository ให้กับ otp app ของเราก่อนเพื่อให้ mix task ของ ecto รู้ว่าเวลาจะจัดการ DB นั้นจะเชื่อมต่อ DB ผ่าน Repository module ไหน

# config/config.exs

config :ecto_sample, ecto_repos: [EctoSample.Repo]
Enter fullscreen mode Exit fullscreen mode

จากนั้นใช้คำสั่ง

mix ecto.gen.migration create_posts_table
Enter fullscreen mode Exit fullscreen mode

โดย create_posts_table คือชื่อ migration file ที่เราต้องการ แล้ว task นี้จะสร้างไฟล์ให้เราที่ path priv/repo/migrations แบบนี้

priv/repo/migrations/20210115233819_create_posts_table.exs
Enter fullscreen mode Exit fullscreen mode

จะเห็นว่าจะมี timestamp ที่ด้านหน้าชื่อที่เราส่งให้ตอนสั่ง generate migration file

เมื่อเราเปิดไฟล์ขึ้นมาจะเห็นโค้ดที่ถูก generate มาไว้ให้แล้วเบื้องต้นแบบนี้

defmodule EctoSample.Repo.Migrations.CreatePostsTable do
  use Ecto.Migration

  def change do

  end
end
Enter fullscreen mode Exit fullscreen mode

สิ่งที่เราต้องทำเพิ่มคือเขียนโค้ดเพื่อสร้าง table ตามที่เราต้องการ ซึ่งโค้ดนั้นก็ยังเป็นโค้ด Elixir โดยอาศัย macro จาก module Ecto.Migration ช่วยในการเขียนโค้ดจัดการสร้าง table ตัวอย่างเช่น

defmodule EctoSample.Repo.Migrations.CreatePostsTable do
  use Ecto.Migration

  def change do
    create table(:posts) do
      add :title, :string
      add :body, :string

      timestamps()
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

เราใช้ create macro เพื่อบอกว่าเราต้องการสร้างสิ่งใหม่ให้กับ DB แล้วก็ใช้ table(:posts) เพื่อบอกว่าสิ่งที่เราจะสร้างนั้นคือ table ชื่อ posts ส่วน do ... end block ที่เราเขียนลงไปจะเป็นรายละเอียดของ column ที่เราต้องการสร้างให้กับ table posts นั่นเอง

จากโค้ดเราสร้าง 2 columns คือ title กับ body โดยมี type เป็น :string ทั้งคู่ซึ่ง type ที่เราใช้ใน migration script จะถูกแปลงเป็น type แต่ละแบบของ DB ขึ้นอยู่กับ DB ที่เราใช้ และ adapter library ที่เราใช้

ส่วน timestamps() เป็นการบอกให้สร้างอีก 2 fields ชื่อ inserted_at กับ updated_at เป็น date time ทั้งคู่ สอง fields นี้จะมีผลกับบางคำสั่งที่ใช้ insert และ update ข้อมูลของ module Repo โดยจะทำการ stamp เวลาที่ใช้ insert กับ update ให้เอง

หลังจากเราเขียนโค้ด migration เสร็จแล้ว เราจะสั่ง mix ecto.migrate เพื่อ run script ที่เราเขียนสิ่งที่ได้คือ table ใน DB ตามที่เราเขียนไว้

$ mix ecto.migrate

06:51:54.202 [info]  == Running 20210115233819 EctoSample.Repo.Migrations.CreatePostsTable.change/0 forward

06:51:54.205 [info]  create table posts

06:51:54.235 [info]  == Migrated 20210115233819 in 0.0s
Enter fullscreen mode Exit fullscreen mode

เมื่อเช็คใน MySQL จะเจอ tables ถูกสร้างมา 2 tables

mysql> show tables;
+-------------------+
| Tables_in_test    |
+-------------------+
| posts             |
| schema_migrations |
+-------------------+
2 rows in set (0.01 sec)
Enter fullscreen mode Exit fullscreen mode

รายละเอียดของ table posts เป็นแบบนี้

mysql> desc posts;
+-------------+-----------------+------+-----+---------+----------------+
| Field       | Type            | Null | Key | Default | Extra          |
+-------------+-----------------+------+-----+---------+----------------+
| id          | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| title       | varchar(255)    | YES  |     | NULL    |                |
| body        | varchar(255)    | YES  |     | NULL    |                |
| inserted_at | datetime        | NO   |     | NULL    |                |
| updated_at  | datetime        | NO   |     | NULL    |                |
+-------------+-----------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
Enter fullscreen mode Exit fullscreen mode

จะเห็นว่า migration script ที่เราเขียนเมื่อสั่ง migrate จะสร้าง column id เป็น primary key และ auto_increment ให้ด้วย

จากนั้นลองดู table schema_migrations เป็นแบบนี้

mysql> desc schema_migrations;
+-------------+----------+------+-----+---------+-------+
| Field       | Type     | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+-------+
| version     | bigint   | NO   | PRI | NULL    |       |
| inserted_at | datetime | YES  |     | NULL    |       |
+-------------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> select * from schema_migrations;
+----------------+---------------------+
| version        | inserted_at         |
+----------------+---------------------+
| 20210115233819 | 2021-01-15 23:51:54 |
+----------------+---------------------+
1 row in set (0.00 sec)
Enter fullscreen mode Exit fullscreen mode

จะเห็นว่ามี 2 columns ซึ่งเมื่อ select ดูก็จะพบเลข version ตรงกับ timestamp ของชื่อไฟล์ 20210115233819_create_posts_table.exs นั่นเอง

หน้าที่ของ table นี้ก็คือให้ task mix ecto.migrate รู้ได้ว่าตอนนี้ schema ของ DB ที่เราจัดการมีการเปลี่ยนแปลงไปโดยขึ้นอยู่กับ migration script ล่าสุดไฟล์ไหนนั่นเอง

ซึ่งทำให้เราสามารถบอก ecto task ให้ทำการ rollback โครงสร้างของ DB ถอยกลับไป version ก่อนหน้าได้ ด้วยคำสั่ง

$ mix ecto.rollback

06:58:49.200 [info]  == Running 20210115233819 EctoSample.Repo.Migrations.CreatePostsTable.change/0 backward

06:58:49.204 [info]  drop table posts

06:58:49.230 [info]  == Migrated 20210115233819 in 0.0s
Enter fullscreen mode Exit fullscreen mode

เมื่อเราสั่ง mix ecto.rollback จะเห็นว่ามันทำการ drop table posts ที่เราสร้างตอนสั่ง mix ecto.migrate ก่อนหน้านี้ พอเราไปดูขอมูลในตาราง schema_migrations อีกรอบจะเห็นแบบนี้

mysql> select * from schema_migrations;
Empty set (0.00 sec)
Enter fullscreen mode Exit fullscreen mode

ข้อมูลถูกลบไปแล้วเพราะเราสั่ง mix ecto.rollback ไป

เราสามารถสั่ง mix ecto.migrate อีกรอบได้ ก็จะได้ posts table กลับมาและ version ใน schema_migrations ก็อัพเดทเป็น migration script ล่าสุดเช่นกัน

สรุป

เราได้เห็นตัวอย่างการใช้ Ecto migration สร้าง table กันไปแล้วซึ่งจริงๆการเปลี่ยนแปลงโครงสร้างเราสามารถใช้ migration script ช่วยได้ ทำให้เราจัดการ rollback ได้ง่ายๆเมื่อสิ่งที่ทำไปผิดหรือไม่ต้องการ

นอกจากนั้น Ecto.Migration module ยังมี macro อื่นๆอีกให้ใช้งานในการจัดการ schema ไม่ใช่แค่การ create table เท่านั้น

Buy Me A Coffee

Top comments (0)