$ olympian --help

Olympian

Laravel-inspired database migrations for Go

Quick Start

Get running in 60 seconds

bash - olympian installation
$ go get github.com/ichtrojan/olympian/cmd/olympian@latest
go: downloading github.com/ichtrojan/olympian v1.0.0
✓ Installation complete
$ olympian migrate create users
Created migration: ./migrations/1735689123_create_users_table.go
# Smart naming: automatically adds create_ prefix and _table suffix
$

Configure Database

.env
DB_DRIVER=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=bandit
DB_USER=root
DB_PASS=
bash - run migrations
$ olympian migrate
Initializing Olympian (creating cmd/migrate/main.go)...
✓ Created cmd/migrate/main.go
Migrating: create_users_table
Migrated: create_users_table
✓ Migrations completed successfully
.env
DB_DRIVER=postgres
DB_HOST=localhost
DB_PORT=5432
DB_NAME=mydb
DB_USER=postgres
DB_PASS=secret
bash - sqlite migrations
$ olympian migrate --driver sqlite3 --dsn ./database.db
✓ Migrations complete

Features

🎯

Fluent API

Chain methods elegantly with a Laravel-inspired syntax that feels natural and readable.

🗄️

Multi-Database

PostgreSQL, MySQL, and SQLite support using standard database/sql package.

🔄

Rollback Support

Full rollback functionality with batch tracking for safe schema changes.

⚙️

.env Configuration

Simple configuration with .env files - no complex connection strings needed.

🔗

Foreign Keys

Full foreign key support with cascading actions and relationship management.

Type-Safe

Leverage Go's type system for compile-time safety and excellent IDE support.

🚀

Auto-Initialization

No setup required! Automatically creates migration runner on first use.

🏷️

Smart Naming

Automatically formats migration names with create_ prefix and _table suffix.

🔒

Keyword Escaping

Automatically handles MySQL reserved keywords like limit, order, and type.

🌱

Database Seeders

Populate your database with test data using structs or maps with automatic snake_case conversion.

🔧

Column Changes

Modify existing column types and properties with the Change() modifier for evolving schemas.

Write Migrations

Clean, expressive syntax for defining your schema

package migrations

import "github.com/ichtrojan/olympian"

func init() {
    olympian.RegisterMigration(olympian.Migration{
        Name: "create_users_table",
        Up: func() error {
            return olympian.Table("users").Create(func() {
                olympian.Uuid("id").Primary()
                olympian.String("email").Unique()
                olympian.String("password")
                olympian.Boolean("verified").Default(false)
                olympian.Timestamps()
            })
        },
        Down: func() error {
            return olympian.Table("users").Drop()
        },
    })
}

Foreign Keys

olympian.Table("posts").Create(func() {
    olympian.Uuid("id").Primary()
    olympian.String("user_id")
    olympian.String("title")
    olympian.Text("content")
    olympian.Foreign("user_id").
        References("id").
        On("users").
        OnDelete("cascade")
    olympian.Timestamps()
})

Inline Foreign Keys

Define foreign keys directly on the column definition:

olympian.Uuid("user_id").
    References("id").
    On("users").
    OnDelete("cascade")

Composite Unique Constraints

Ensure uniqueness across multiple columns:

olympian.Table("subscriptions").Create(func() {
    olympian.Uuid("id").Primary()
    olympian.Uuid("user_id")
    olympian.Uuid("plan_id")

    // User can only subscribe to each plan once
    olympian.Unique("user_id", "plan_id")

    // With custom constraint name
    olympian.Unique("user_id", "plan_id").Name("unique_user_plan")
})

Modify Tables

olympian.Table("users").Modify(func() {
    olympian.Text("bio").Nullable()
    olympian.String("avatar").Nullable()
    olympian.Integer("age").After("name")
})

Change Existing Columns

Use the Change() modifier to alter existing column types or properties.

olympian.Table("invoices").Modify(func() {
    // Change from Enum to String
    olympian.String("currency").Default("GBP").Change()

    // Make a column nullable
    olympian.Text("notes").Nullable().Change()

    // Change column type
    olympian.BigInteger("amount").Change()
})

Note: MySQL uses MODIFY COLUMN, PostgreSQL uses ALTER COLUMN. SQLite does not support column modifications.

Raw SQL

For complex queries or database-specific operations, access the underlying connection:

db, dialect := olympian.GetDB()

// Run any raw SQL
_, err := db.Exec("CREATE EXTENSION IF NOT EXISTS postgis")

// Use in migrations
{
    Name: "add_postgis_extension",
    Up: func() error {
        db, _ := olympian.GetDB()
        _, err := db.Exec("CREATE EXTENSION IF NOT EXISTS postgis")
        return err
    },
    Down: func() error {
        db, _ := olympian.GetDB()
        _, err := db.Exec("DROP EXTENSION IF EXISTS postgis")
        return err
    },
}

CLI Commands

Powerful command-line interface for managing migrations

olympian migrate

Run all pending migrations

$ olympian migrate
Migrating: create_users_table
Migrated: create_users_table
olympian migrate create [name]

Create a new migration file with smart naming (automatically adds create_ and _table)

$ olympian migrate create posts
Created migration: ./migrations/1735689456_create_posts_table.go
# Also works: create_posts, posts_table, create_posts_table
olympian migrate rollback

Rollback the last batch of migrations

$ olympian migrate rollback
Rolling back: create_users_table
Rolled back: create_users_table
olympian migrate status

Show migration status

$ olympian migrate status
------------------------------------------------------------
| Status | Migration |
------------------------------------------------------------
| Ran | create_users_table |
| Pending | create_posts_table |
------------------------------------------------------------

Column Types

Rich set of column types for any schema

Uuid(name)

UUID primary keys

String(name)

VARCHAR(255)

Text(name)

Long text content

TinyInteger(name)

Small integers (TINYINT)

Integer(name)

Integer numbers

BigInteger(name)

Large integers (BIGINT)

Increments(name)

Auto-increment INT PK

BigIncrements(name)

Auto-increment BIGINT PK

Boolean(name)

True/false values

Timestamp(name)

Date and time

Json(name)

JSON/JSONB data

Decimal(name, p, s)

Precise decimals

Modifiers

olympian.String("email").Nullable()
olympian.Uuid("id").Primary()
olympian.String("username").Unique()
olympian.Boolean("active").Default(true)
olympian.Integer("age").After("name")
olympian.Integer("id").AutoIncrement()
olympian.String("status").Change()           // Modify existing column
olympian.String("email").Index()             // Add index (auto-named)
olympian.String("slug").IndexWithName("idx") // Add index with custom name

Database Seeders

Populate your database with test or initial data

bash - create and run seeders
$ olympian seed create user
Created seeder: seeders/user_seeder.go
$ olympian seed run
Seeding: user
Seeded: user
Database seeding completed successfully
$ olympian seed run user product
# Run specific seeders by name

Using Structs

Field names are automatically converted to snake_case. time.Time is converted to timestamp format. Pass a slice for multiple records.

type User struct {
    ID        string
    Name      string
    UserAge   int       // becomes user_age
    CreatedAt time.Time // converted to timestamp
}

olympian.Seed("users", []User{
    {ID: "1", Name: "John", UserAge: 25, CreatedAt: time.Now()},
    {ID: "2", Name: "Jane", UserAge: 30, CreatedAt: time.Now()},
})

Using Maps

olympian.Seed("users",
    map[string]interface{}{
        "id":    "uuid-1",
        "name":  "John Doe",
        "email": "john@example.com",
    },
)

Seeder File Structure

package seeders

import "github.com/ichtrojan/olympian"

func init() {
    olympian.RegisterSeeder(olympian.Seeder{
        Name: "user",
        Run: func() error {
            return olympian.Seed("users",
                map[string]interface{}{
                    "id":   "uuid-here",
                    "name": "John Doe",
                },
            )
        },
    })
}

Why Olympian?

Olympian brings the elegance of Laravel's migration system to Go. If you've ever wished for a more expressive way to manage database schemas in Go, Olympian is your answer.

  • Familiar - Laravel-inspired syntax
  • Simple - Configure once with .env
  • Powerful - Full schema management
  • Safe - Automatic rollbacks
  • Fast - No ORM overhead