Mengelola Database Migration di Project Golang

By Rizky Kurniawan - April 27, 2025 ~6 mins read

ruangdeveloper.com - Halo-halo! Beberapa waktu yang lalu bekerja dengan project golang yang menggunakan golang-migrate untuk mengelola database migration. Seperti pada umumnya, project ini dikerjakan oleh beberapa developer dengan pembagian tugas yang sudah diatur. Development experience masih terasa menyenangkan hingga tiba saat dimana terjadi kekacauan pada database migration yang kami buat. Jika dituliskan, kira-kira kasusnya seperti ini:

  • Developer A membuat migrasi untuk membuat tabel users
  • Developer B membuat migrasi untuk mengedit tabel roles
  • Developer A dan B open merge request
  • Merge request dari developer B diterima, migrasi dijalankan
  • Masalah: Merge request dari developer A diterima, migrasi dijalankan tapi tidak tereksekusi karena secara history, migrasi dari developer B lebih terbaru dan golang-migrate menganggap tidak ada migrasi lagi yang perlu dijalankan.

Dari pengalaman itu, saya jadi merindukan kemudahan migrasi database yang dimiliki oleh Laravel, hahaha.

Singkatnya, pengalaman itu menghasilkan sebuah ide untuk membuat database migration tool versi saya sendiri yang menyimpan semua history migrasi seperti yang dilakukan Laravel, dan jadilah Qafoia.

Apa itu Qafoia?

Qafoia adalah sebuah package opensource yang dapat kita gunakan untuk mengelola migrasi database di project golang. Fitur-fitur yang ditawarkan antara lain sebagai berikut:

  • Registrasikan migrasi menggunakan go struct, tulis sql script di dalamnya.
  • Jalankan migrasi, rollback, refresh, reset dengan mudah.
  • Debug SQL script saat migrasi dijalankan.
  • Otomatis generate template go struct untuk menulis migrasi.
  • Track history migrasi pada tabel khusus yang dapat disesuaikan namanya.
  • Saat ini tersedia MySQL dan Postgres driver yang siap digunakan
  • Dapat dengan mudah membuat driver versi kamu sendiri.

Penggunaan

Qafoia dirancang agar mudah untuk digunakan tanpa konfigurasi yang terlalu rumit. Kamu dapat mengikuti langkah-langkah berikut.

Install Qafoia

go get -u github.com/ruangdeveloper/qafoia

Inisialisasi Driver

Pada contoh ini kita menggunakan MySqlDriver yang sudah disediakan.

driver, err := qafoia.NewMySqlDriver(
    "localhost",
    "3306",
    "db username",
    "db password",
    "db name",
    "utf8mb4"
)

Inisialisasi Qafoia

qafoia, err := qafoia.New(&qafoia.Config{
    Driver              : driver, // driver yang sudah diinisialisasi
    MigrationFilesDir   : "migrations", // default migrations
    MigrationTableName  : "migrations", // default migrations
})

Registrasi Migrasi

err := qafoia.Register(
  // nanti migration file kita registrasi ke sini
)

Setelah semua diinisialisasi, kita dapat melakukan beberapa operasi dasar migrasi seperti berikut:

List Migration

list, err := q.List(context.Background())

if err != nil {
    log.Fatal(err)
}

list.Print()

Contoh output:

+-----------------------------------+-------------+-------------+
| Migration Name                    | Is Executed | Executed At |
+-----------------------------------+-------------+-------------+
| 20250427064746_create_users_table | false       | N/A         |
+-----------------------------------+-------------+-------------+

Output akan menyesuaikan dengan migrasi yang kita registrasikan.

Create Migration

err = q.Create("create_users_table")

if err != nil {
    log.Fatal(err)
}

Contoh output:

2025/04/27 06:47:46 migration file created: migrations/20250427064746_create_users_table.go

Migration file akan disimpan pada direktori yang sudah diatur ketika inisialisasi Qafoia.

Contoh migration file yang dibuat:

package migrations

type M20250427064746CreateUsersTable struct{}

func (m *M20250427064746CreateUsersTable) Name() string {
	// Don't change this name
	return "20250427064746_create_users_table"
}

func (m *M20250427064746CreateUsersTable) UpScript() string {
	// Write your migration SQL here
	return ""
}

func (m *M20250427064746CreateUsersTable) DownScript() string {
	// Write your rollback SQL here
	return ""
}

Kita bisa menuliskan script SQL untuk migrasi dalam fungsi UpScript() dan menuliskan script SQL untuk rollback dalam fungsi DownScript().

Setelah file migrasi dan script SQL dibuat, kita bisa meregistrasikannya seperti berikut:

err := qafoia.Register(
  &migrations.M20250427064746CreateUsersTable{},
)

Run Migration

Untuk menjalankan migrasi, kita bisa menggunakan fungsi Migrate()

err = q.Migrate(context.Background())

if err != nil {
    log.Fatal(err)
}

Contoh output:

2025/04/27 06:56:44 ๐Ÿš€ Applying 1 migration(s)...
2025/04/27 06:56:44 ๐Ÿ“ฆ Migrating: 20250427064746_create_users_table
2025/04/27 06:56:44 โœ… Migrated: 20250427064746_create_users_table

Cek ke tabel migrations di database

name                             |executed_at            |
---------------------------------+-----------------------+
20250427064746_create_users_table|2025-04-27 06:56:44.000|

Rollback Migration

Untuk melakukan rollback, kita bisa menggunakan fungsi Rollback(). Fungsi ini menerima parameter step yang dapat kita gunakan untuk menentukan akan rollback sampai berapa migrasi.

err = c.qafoia.Rollback(context.Background(), 1)
if err != nil {
    log.Fatal(err)
}

Contoh output:

2025/04/27 07:02:15 ๐Ÿ” Rolling back 1 migration(s)...
2025/04/27 07:02:15 ๐Ÿ”„ Rolling back: 20250427064746_create_users_table
2025/04/27 07:02:15 โœ… Rolled back: 20250427064746_create_users_table

Fresh Migration

Fresh migration akan menghapus semua tabel dalam database lalu menjalankan semua migrasi dari awal. Untuk melakukan fresh migration, kita bisa menggunakan fungsi Fresh().

err = c.qafoia.Fresh(context.Background())
if err != nil {
    log.Fatal(err)
}

Contoh output:

2025/04/27 07:06:33 ๐Ÿงน Cleaning database...
2025/04/27 07:06:33 ๐Ÿš€ Running fresh migrations...
2025/04/27 07:06:33 ๐Ÿš€ Applying 1 migration(s)...
2025/04/27 07:06:33 ๐Ÿ“ฆ Migrating: 20250427064746_create_users_table
2025/04/27 07:06:33 โœ… Migrated: 20250427064746_create_users_table
2025/04/27 07:06:33 โœ… Fresh migration completed successfully

Reset Migration

Reset migration akan menjalankan rollback semua migrasi yang sudah dieksekusi kemudian menjalankan migrasi ulang. Untuk melakukan reset migration, kita bisa menggunakan fungsi Reset().

err = c.qafoia.Reset(context.Background())
if err != nil {
    log.Fatal(err)
}

Contoh output:

2025/04/27 07:09:01 ๐Ÿ” Resetting 1 executed migration(s)...
2025/04/27 07:09:01 ๐Ÿ” Rolling back 1 migration(s)...
2025/04/27 07:09:01 ๐Ÿ”„ Rolling back: 20250427064746_create_users_table
2025/04/27 07:09:01 โœ… Rolled back: 20250427064746_create_users_table
2025/04/27 07:09:01 ๐Ÿš€ Applying 1 migration(s)...
2025/04/27 07:09:01 ๐Ÿ“ฆ Migrating: 20250427064746_create_users_table
2025/04/27 07:09:01 โœ… Migrated: 20250427064746_create_users_table
2025/04/27 07:09:01 โœ… Migration reset completed successfully

Clean Migration

Clean akan menghapus semua tabel yang ada di database. Untuk melakukan clean migration, kita bisa menggunakan fungsi Clean().

err = c.qafoia.Clean(context.Background())
if err != nil {
    log.Fatal(err)
}

Contoh output:

2025/04/27 07:10:31 ๐Ÿงน Cleaning database...
2025/04/27 07:10:31 โœ… Database cleaned successfully

CLI Helper

Qafoia dirancang agar kita bisa menggunakan cara kita sendiri dalam mengeksekusi operasi migrasi. Namun jika kita ingin cara yang cepat, kita bisa memanfaatkan CLI helper yang sudah disediakan. Dengan menggunakan cli helper, kita bisa menjalankan migrasi melalui command line. Beberapa perintah yang tersedia sebagai berikut:

  • clean - Clean database (delete all tables)
  • create - Create a new migration
  • help - Help about any command
  • list - List all migrations
  • migrate - Run all pending migrations (use –fresh flag for fresh migration)
  • reset - Rollback all migrations and re-run all migrations
  • rollback - Rollback the last migration (use –step flag for setting rollback step)

Untuk menggunakan CLI helper, cukup tambahkan kode berikut:

cli, err := qafoia.NewCli(qafoia.CliConfig{
    Qafoia: qafoia, // Qafoia yang sudah diinisialisasi
})

if err != nil {
    log.Fatal(err)
}

err = cli.Execute(context.Background())

if err != nil {
    log.Fatal(err)
}

Setelah inisialisasi CLI, kita bisa menjalankan perintah seperti berikut:

Menjalankan migrasi

go run main.go migrate

Atau dengan fresh

go run main.go migrate --fresh

Membuat file migrasi

go run main.go create "Create Users Table"

Menampilkan list migrasi

go run main.go list

Rollback migrasi

go run main.go rollback

Atau dengan menentukan step

go run main.go rollback --step 2

Reset migrasi

go run main.go reset

Clean database

go run main.go clean

Contoh File Akhir

File: main.go

package main

import (
    "context"
    "log"
    "test_qafoia_published/migrations"

    "github.com/ruangdeveloper/qafoia"
)

func main() {
    d, err := qafoia.NewMySqlDriver(
        "localhost",
        "3306",
        "db user",
        "db pass",
        "db name",
        "utf8mb4",
    )

    if err != nil {
        log.Fatal(err)
    }

    q, err := qafoia.New(&qafoia.Config{
        Driver:             d,
        MigrationFilesDir:  "migrations",
        MigrationTableName: "migrations",
    })

    if err != nil {
        log.Fatal(err)
    }

    err = q.Register(
        &migrations.M20250427064746CreateUsersTable{},
    )

    if err != nil {
        log.Fatal(err)
    }

    cli, err := qafoia.NewCli(qafoia.CliConfig{
	      Qafoia: q,
    })

    if err != nil {
        log.Fatal(err)
    }

    err = cli.Execute(context.Background())

    if err != nil {
        log.Fatal(err)
    }
}

Kesimpulan

Dari pengalaman menggunakan golang-migrate di proyek Golang, saya menemukan tantangan ketika beberapa developer membuat migrasi dalam waktu berdekatan. Karena golang-migrate hanya mencatat satu versi terakhir yang dijalankan, tidak semua histori migrasi tersimpan. Akibatnya, migrasi bisa saling bertabrakan, urutan migrasi menjadi tidak konsisten, dan potensi error di database pun semakin besar. Dari situ lahir ide untuk membuat sebuah tool baru yang lebih terstruktur, seperti konsep migrasi di Laravel.

Qafoia mengelola migrasi menggunakan struct, mencatat histori di tabel khusus, dan sudah mendukung MySQL serta Postgres. Semua operasi seperti migrate, rollback, fresh, reset, hingga clean database dapat dilakukan dengan perintah yang sederhana. Tersedia juga CLI helper untuk mempermudah penggunaan.

Karena ini adalah proyek open source, saya mengundang teman-teman developer yang tertarik untuk ikut berkontribusi, memberikan masukan, atau membantu mengembangkan Qafoia ke depannya. ๐Ÿš€

Ingin Berdiskusi?

Yuk bergabung di Grup Telegram Ruang Developer atau mulai diskusi melalui GitHub. See You!

Dapatkan contoh source code project backend, frontend, atau fullstack untuk kamu amati, tiru, dan modifikasi sesuka hati. Klik untuk melihat detail!
comments powered by Disqus

Berlangganan Gratis

Kamu akan menerima email update dari Ruang Developer

Beri Dukungan

Beri dukungan, dapatkan full source code project web untuk bahan referensi, tiru, dan modifikasi.
Lightbox