วันนี้จะลองสร้าง table ผ่าน Ecto Migration กัน
เริ่มแรกเราต้อง config repository ให้กับ otp app ของเราก่อนเพื่อให้ mix task ของ ecto รู้ว่าเวลาจะจัดการ DB นั้นจะเชื่อมต่อ DB ผ่าน Repository module ไหน
# config/config.exs
config :ecto_sample, ecto_repos: [EctoSample.Repo]
จากนั้นใช้คำสั่ง
mix ecto.gen.migration create_posts_table
โดย create_posts_table คือชื่อ migration file ที่เราต้องการ แล้ว task นี้จะสร้างไฟล์ให้เราที่ path priv/repo/migrations แบบนี้
priv/repo/migrations/20210115233819_create_posts_table.exs
จะเห็นว่าจะมี timestamp ที่ด้านหน้าชื่อที่เราส่งให้ตอนสั่ง generate migration file
เมื่อเราเปิดไฟล์ขึ้นมาจะเห็นโค้ดที่ถูก generate มาไว้ให้แล้วเบื้องต้นแบบนี้
defmodule EctoSample.Repo.Migrations.CreatePostsTable do
use Ecto.Migration
def change do
end
end
สิ่งที่เราต้องทำเพิ่มคือเขียนโค้ดเพื่อสร้าง 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
เราใช้ 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
เมื่อเช็คใน MySQL จะเจอ tables ถูกสร้างมา 2 tables
mysql> show tables;
+-------------------+
| Tables_in_test |
+-------------------+
| posts |
| schema_migrations |
+-------------------+
2 rows in set (0.01 sec)
รายละเอียดของ 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)
จะเห็นว่า 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)
จะเห็นว่ามี 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
เมื่อเราสั่ง mix ecto.rollback จะเห็นว่ามันทำการ drop table posts ที่เราสร้างตอนสั่ง mix ecto.migrate ก่อนหน้านี้ พอเราไปดูขอมูลในตาราง schema_migrations อีกรอบจะเห็นแบบนี้
mysql> select * from schema_migrations;
Empty set (0.00 sec)
ข้อมูลถูกลบไปแล้วเพราะเราสั่ง 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 เท่านั้น

Top comments (0)