Skip to content

Latest commit

 

History

History
191 lines (148 loc) · 5.92 KB

File metadata and controls

191 lines (148 loc) · 5.92 KB

Conditional Migrations (Profiles)

This feature lets a single migrations directory contain files that are applied only against a specific deployment target — for example normal MongoDB, AWS DocumentDB, or a sharded DocumentDB cluster where some operations are restricted.

Filename convention

<version>_<identifier>[.<profile>].(up|down).<ext>
  • <version> — the usual numeric ordering (001, 20240101120000, …).
  • <identifier> — descriptive name, e.g. create_user.
  • <profile>optional deployment profile, e.g. mongo, documentdb, documentdb-sharded. Letters, digits, -, and _ are allowed.
  • <ext> — file extension, e.g. sql, json.

Examples in one directory:

001_create_user.up.json                                # default (untagged)
001_create_user.down.json
001_create_user.mongo.up.json                          # mongo-only variant
001_create_user.mongo.down.json
001_create_user.documentdb-sharded.up.json             # documentdb-sharded only variant
001_create_user.documentdb-sharded.down.json
002_enable_change_streams.mongo.up.json                # mongo-only variant
002_enable_change_streams.mongo.down.json

Selection rules

The runtime selects files based on the active profile. Profile names are arbitrary strings — mongo, documentdb, and documentdb-sharded below are illustrative, not reserved.

Active profile Which files are loaded
(empty / unset) only files without a profile tag
any name X files tagged .X. and untagged files

Override rule:

When the active profile is X and both an untagged file and a .X. file exist for the same (version, direction), the .X. file wins. The untagged file acts as the default; the tagged file is the per-profile override.

Other notes:

  • A file tagged with a profile different from the active one is never loaded.
  • Duplicate detection key is (version, direction, profile)not the identifier. So 001_foo.up.sql + 001_bar.up.sql is a duplicate (same untagged slot), 001_foo.mongo.up.sql + 001_bar.mongo.up.sql is a duplicate (same mongo slot), but 001_foo.up.sql + 001_foo.mongo.up.sql is not a duplicate (different profiles — the tagged file is the override). Violations surface as source.ErrDuplicateMigration at source-driver init time.
  • The numeric <version> is what gets written to the database's schema_migrations record, regardless of which profile-variant ran. The parsed Migration.Identifier is suffixed with [profile] so log lines make the chosen variant obvious.

How to choose a profile

CLI flag

migrate -source file://./migrations \
        -database "mongodb://localhost:27017/mydb" \
        -profile mongo \
        up

Environment variable

-profile falls back to $MIGRATE_PROFILE:

export MIGRATE_PROFILE=documentdb-sharded
migrate -source file://./migrations \
        -database "mongodb://shared-docdb.cluster.local:27017/mydb" \
        up

The CLI flag takes precedence over the env var.

Programmatic (Go)

import (
    "github.com/AccelByte/migrate/v4"
    _ "github.com/AccelByte/migrate/v4/database/mongodb"
    _ "github.com/AccelByte/migrate/v4/source/file"
)

m, err := migrate.New("file://./migrations", "mongodb://localhost:27017/mydb")
if err != nil { panic(err) }
defer m.Close()

// returns false if the source driver does not implement source.ProfileAware
if !m.SetSourceProfile("documentdb") {
    panic("source driver does not support profiles")
}

if err := m.Up(); err != nil && err != migrate.ErrNoChange {
    panic(err)
}

When using a hand-built source driver via iofs.New:

import (
    "embed"
    "github.com/AccelByte/migrate/v4"
    "github.com/AccelByte/migrate/v4/source/iofs"
)

//go:embed migrations/*
var fsys embed.FS

src, err := iofs.New(fsys, "migrations")
if err != nil { panic(err) }

// Set the profile before passing to migrate.NewWithSourceInstance.
src.(source.ProfileAware).SetProfile("mongo")

m, err := migrate.NewWithSourceInstance("iofs", src, dbURL)

Operational notes

  • Pick one profile per database and stick with it. Switching profiles on the same database can produce inconsistent state because both variants share the same version number.

  • Source-driver support matrix:

    Source driver Profile-aware?
    file
    iofs
    httpfs, godoc_vfs, pkger ❌ (share httpfs.PartialDriver — could be added later)
    aws_s3, bitbucket, github, github_ee, gitlab, go_bindata, google_cloud_storage, stub

    If -profile is set against an unsupported driver, the CLI logs a warning and loads all files — including profile-tagged ones, which is almost certainly not what you want. Pin one of the supported drivers if you rely on profiles.

End-to-end example

Directory:

migrations/
  001_users.up.json
  001_users.down.json
  001_users.documentdb-sharded.up.json
  001_users.documentdb-sharded.down.json
  002_indexes.mongo.up.json
  002_indexes.mongo.down.json
  002_indexes.documentdb.up.json
  002_indexes.documentdb.down.json

Runs:

# Plain mongo deployment:
#   v1: 001_users.up.json (untagged — no mongo override exists)
#   v2: 002_indexes.mongo.up.json (mongo variant)
MIGRATE_PROFILE=mongo migrate -path migrations -database "$URL" up

# AWS DocumentDB deployment:
#   v1: 001_users.up.json (untagged — no documentdb override)
#   v2: 002_indexes.documentdb.up.json (documentdb variant)
MIGRATE_PROFILE=documentdb migrate -path migrations -database "$URL" up

# Shared DocumentDB deployment:
#   v1: 001_users.documentdb-sharded.up.json (override wins over untagged)
#   v2: skipped — neither an untagged nor a documentdb-sharded variant exists
MIGRATE_PROFILE=documentdb-sharded migrate -path migrations -database "$URL" up

# No profile — applies only the untagged files: v1 only.
migrate -path migrations -database "$URL" up