Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.25', '1.26']
go-version: ['1.23', '1.24', '1.25']

steps:
- name: Checkout code
Expand All @@ -44,6 +44,7 @@ jobs:
run: |
go test -v -cover -race ./... -coverprofile=coverage.txt
- name: Upload coverage reports to Codecov
if: matrix.go-version == '1.25'
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ go.work.sum
.idea/
.vscode/
.serena/
.claude/
43 changes: 0 additions & 43 deletions AGENTS.md

This file was deleted.

48 changes: 0 additions & 48 deletions GEMINI.md

This file was deleted.

122 changes: 106 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func downCreateUsersTable(c schema.Context) error {

### Running Migrations

For a complete CLI setup example, see [examples/basic](examples/basic/). For quick setup, use the CLI helpers below.
For a complete stdlib-only example, see [examples/basic](examples/basic/). For quick setup with a CLI framework, use the helpers below.

### CLI Helpers

Expand Down Expand Up @@ -90,6 +90,7 @@ func main() {
DB: db,
Dialect: "pgx",
MigrationsDir: "./migrations",
AllowMissing: false, // set true to allow out-of-order migrations
}

cmd := migriscli.NewCLI(cfg)
Expand Down Expand Up @@ -124,6 +125,7 @@ func main() {
DB: db,
Dialect: "pgx",
MigrationsDir: "./migrations",
AllowMissing: false, // set true to allow out-of-order migrations
}

cmd := migriscobra.NewCLI(cfg)
Expand All @@ -133,7 +135,7 @@ func main() {
}
```

Both CLI helpers support all migration commands: `create`, `up`, `up-to`, `down`, `down-to`, `reset`, `status` with `--dry-run` support.
Both CLI helpers support all migration commands: `create`, `up`, `up-to`, `down`, `down-to`, `reset`, `status`. The `--dry-run` flag is available per-command. `AllowMissing` in `Config` applies to all run operations.

## Schema Builder API

Expand Down Expand Up @@ -163,29 +165,117 @@ schema.Table(c, "posts", func(table *schema.Blueprint) {
})
```

## Migration Operations
## Options

Migris supports all standard migration operations:
Migris uses two distinct option types:

### `MigrisOption` — constructor options

Passed to `New()` to configure the migrator instance:

```go
m, err := migris.New("pgx",
migris.WithDB(db),
migris.WithMigrationDir("./migrations"),
migris.WithTableName("schema_migrations"),
migris.WithRegistry(registry),
)
```

| Option | Description |
|---|---|
| `WithDB(db)` | Existing `*sql.DB` connection (caller manages lifecycle) |
| `WithDSN(dsn)` | Open a new connection from DSN string (migrator manages lifecycle, call `Close()`) |
| `WithMigrationDir(dir)` | Directory for SQL migration files (default: `"migrations"`) |
| `WithTableName(name)` | Migrations tracking table name (default: `"schema_migrations"`) |
| `WithRegistry(r)` | Use an isolated migration registry instead of the global one |

`WithDB` and `WithDSN` are mutually exclusive; `WithDB` takes precedence if both are set.

When using `WithDSN`, the migrator opens the connection internally and owns it. Call `Close()` when done:

```go
m, err := migris.New("pgx",
migris.WithDSN("postgres://user:pass@localhost:5432/mydb"),
migris.WithMigrationDir("./migrations"),
)
if err != nil {
log.Fatal(err)
}
defer m.Close()

if err := m.Up(); err != nil {
log.Fatal(err)
}
```

When using `WithDB`, the caller owns the connection lifecycle:

```go
db, err := sql.Open("pgx", os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal(err)
}
defer db.Close()

m, err := migris.New("pgx",
migris.WithDB(db),
migris.WithMigrationDir("./migrations"),
)
```

### `Option` — run-time options

Passed per-operation to control execution behaviour:

```go
// Dry-run: print SQL without applying changes
migrator.Up(migris.WithDryRun(true))
migrator.Down(migris.WithDryRun(true))
migrator.Reset(migris.WithDryRun(true))

// Allow out-of-order migrations
migrator.Up(migris.WithAllowMissing(true))

// Combine options
migrator.UpTo(20250101000005, migris.WithDryRun(true), migris.WithAllowMissing(true))
```

| Option | Description |
|---|---|
| `WithDryRun(bool)` | Preview SQL without executing |
| `WithAllowMissing(bool)` | Apply out-of-order migrations instead of failing |

All operation methods accept run-time options:

```go
migrator.Up() // Run all pending migrations
migrator.Down() // Rollback the last migration
migrator.Reset() // Rollback all migrations
migrator.Status() // Show migration status
migrator.Create(name) // Create a new migration file
migrator.Up(opts...)
migrator.UpTo(version, opts...)
migrator.Down(opts...)
migrator.DownTo(version, opts...)
migrator.Reset(opts...)

// Context variants
migrator.UpContext(ctx, opts...)
migrator.UpToContext(ctx, version, opts...)
migrator.DownContext(ctx, opts...)
migrator.DownToContext(ctx, version, opts...)
migrator.ResetContext(ctx, opts...)

// No run-time options
migrator.Status()
migrator.Create(name)
```

### Dry-Run Mode

Preview migrations without executing them:

```bash
# Preview pending migrations
go run main.go --dry-run up

# Preview rollback operations
go run main.go --dry-run down
go run main.go --dry-run reset
```go
// In code
if err := migrator.Up(migris.WithDryRun(true)); err != nil {
log.Fatal(err)
}
```

Dry-run mode shows:
Expand Down
Loading
Loading