Skip to content

Commit 624631f

Browse files
committed
✨ feat(mongodb): add migration framework and helpers
- Introduced a MongoDB migration package for the GOE framework (`core/mongodb/migrate`). - Added configuration options for handling migrations (e.g., timeouts, transactions, locking, schema versioning). - Provided developer-friendly migration helpers for schema, index, and field operations. - Included distributed locking, checksum verification, and dry-run support for safe migrations. - Documented usage, configuration, and integration details in `doc.go`. - Defined comprehensive error handling for migration-related errors. - Integrated utility operations and progress tracking for bulk updates.
1 parent cb85e98 commit 624631f

File tree

14 files changed

+4234
-10
lines changed

14 files changed

+4234
-10
lines changed

contract/migrator.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package contract
2+
3+
import (
4+
"context"
5+
"time"
6+
)
7+
8+
// Migrator defines the interface for MongoDB migrations
9+
type Migrator interface {
10+
// Up runs all pending migrations
11+
Up(ctx context.Context) (*MigrationResult, error)
12+
13+
// UpTo runs migrations up to and including the specified version
14+
UpTo(ctx context.Context, version int64) (*MigrationResult, error)
15+
16+
// Down rolls back N migrations
17+
Down(ctx context.Context, steps int) (*MigrationResult, error)
18+
19+
// DownTo rolls back to a specific version (exclusive)
20+
DownTo(ctx context.Context, version int64) (*MigrationResult, error)
21+
22+
// Reset rolls back all applied migrations
23+
Reset(ctx context.Context) (*MigrationResult, error)
24+
25+
// Redo rolls back then re-applies the last N migrations
26+
Redo(ctx context.Context, steps int) (*MigrationResult, error)
27+
28+
// Status returns the status of all migrations
29+
Status(ctx context.Context) ([]MigrationStatusEntry, error)
30+
31+
// Pending returns migrations that haven't been applied yet
32+
Pending(ctx context.Context) ([]MigrationInfo, error)
33+
34+
// Version returns the current schema version
35+
Version(ctx context.Context) (int64, error)
36+
37+
// DryRun simulates migrations without applying
38+
DryRun(ctx context.Context) (*MigrationResult, error)
39+
40+
// VerifyChecksums verifies all applied migrations' checksums
41+
VerifyChecksums(ctx context.Context) error
42+
43+
// ClearDirty clears the dirty state for manual intervention
44+
ClearDirty(ctx context.Context, version int64) error
45+
}
46+
47+
// MigrationResult contains the result of a migration operation
48+
type MigrationResult struct {
49+
// Applied contains the versions that were successfully applied
50+
Applied []int64
51+
52+
// RolledBack contains the versions that were rolled back
53+
RolledBack []int64
54+
55+
// Skipped contains the versions that were skipped
56+
Skipped []int64
57+
58+
// Duration is the total time taken for the operation
59+
Duration time.Duration
60+
61+
// DryRun indicates if this was a dry run
62+
DryRun bool
63+
}
64+
65+
// MigrationStatusEntry represents the status of a single migration
66+
type MigrationStatusEntry struct {
67+
Version int64
68+
Name string
69+
Status string // "applied", "pending", "dirty"
70+
AppliedAt *time.Time
71+
Batch int
72+
}
73+
74+
// MigrationInfo provides basic information about a migration
75+
type MigrationInfo struct {
76+
Version int64
77+
Name string
78+
}

core/mongodb/migrate/config.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package migrate
2+
3+
import (
4+
"time"
5+
6+
"go.oease.dev/goe/v2/contract"
7+
)
8+
9+
// Config holds the migration system configuration
10+
type Config struct {
11+
// Collection is the name of the collection used to track migration state
12+
Collection string
13+
14+
// Timeout is the maximum duration for a single migration
15+
Timeout time.Duration
16+
17+
// LockTimeout is the maximum duration to hold the migration lock
18+
LockTimeout time.Duration
19+
20+
// LockHeartbeat is the interval for lock heartbeat updates
21+
LockHeartbeat time.Duration
22+
23+
// UseTransactions enables transaction support for migrations
24+
// Requires MongoDB replica set
25+
UseTransactions bool
26+
27+
// VerifyChecksums enables checksum verification on startup
28+
VerifyChecksums bool
29+
30+
// AutoMigrate enables automatic migration on application start
31+
AutoMigrate bool
32+
33+
// VersionScheme determines how versions are generated
34+
// "sequential" - 1, 2, 3... (default)
35+
// "timestamp" - Unix timestamp based
36+
VersionScheme string
37+
38+
// SchemaVersionField is the field name for document-level schema versioning
39+
SchemaVersionField string
40+
41+
// DryRunByDefault enables dry-run mode by default
42+
DryRunByDefault bool
43+
}
44+
45+
// DefaultConfig returns the default migration configuration
46+
func DefaultConfig() *Config {
47+
return &Config{
48+
Collection: "_goe_migrations",
49+
Timeout: 5 * time.Minute,
50+
LockTimeout: 30 * time.Minute,
51+
LockHeartbeat: 30 * time.Second,
52+
UseTransactions: true,
53+
VerifyChecksums: true,
54+
AutoMigrate: false,
55+
VersionScheme: "sequential",
56+
SchemaVersionField: "_goe_sv",
57+
DryRunByDefault: false,
58+
}
59+
}
60+
61+
// LoadConfig loads configuration from GOE config
62+
func LoadConfig(config contract.Config) *Config {
63+
cfg := DefaultConfig()
64+
65+
// Collection name
66+
if collection := config.GetString("MONGODB_MIGRATE_COLLECTION"); collection != "" {
67+
cfg.Collection = collection
68+
}
69+
70+
// Timeout
71+
if timeout := config.GetDuration("MONGODB_MIGRATE_TIMEOUT"); timeout > 0 {
72+
cfg.Timeout = timeout
73+
}
74+
75+
// Lock timeout
76+
if lockTimeout := config.GetDuration("MONGODB_MIGRATE_LOCK_TIMEOUT"); lockTimeout > 0 {
77+
cfg.LockTimeout = lockTimeout
78+
}
79+
80+
// Lock heartbeat
81+
if lockHeartbeat := config.GetDuration("MONGODB_MIGRATE_LOCK_HEARTBEAT"); lockHeartbeat > 0 {
82+
cfg.LockHeartbeat = lockHeartbeat
83+
}
84+
85+
// Use transactions - default true, explicit false to disable
86+
if config.Has("MONGODB_MIGRATE_USE_TRANSACTIONS") {
87+
cfg.UseTransactions = config.GetBool("MONGODB_MIGRATE_USE_TRANSACTIONS")
88+
}
89+
90+
// Verify checksums - default true, explicit false to disable
91+
if config.Has("MONGODB_MIGRATE_VERIFY_CHECKSUMS") {
92+
cfg.VerifyChecksums = config.GetBool("MONGODB_MIGRATE_VERIFY_CHECKSUMS")
93+
}
94+
95+
// Auto migrate - default false, explicit true to enable
96+
if config.Has("MONGODB_MIGRATE_AUTO") {
97+
cfg.AutoMigrate = config.GetBool("MONGODB_MIGRATE_AUTO")
98+
}
99+
100+
// Version scheme
101+
if scheme := config.GetString("MONGODB_MIGRATE_VERSION_SCHEME"); scheme != "" {
102+
cfg.VersionScheme = scheme
103+
}
104+
105+
// Schema version field
106+
if field := config.GetString("MONGODB_MIGRATE_SCHEMA_VERSION_FIELD"); field != "" {
107+
cfg.SchemaVersionField = field
108+
}
109+
110+
// Dry run by default
111+
if config.Has("MONGODB_MIGRATE_DRY_RUN") {
112+
cfg.DryRunByDefault = config.GetBool("MONGODB_MIGRATE_DRY_RUN")
113+
}
114+
115+
return cfg
116+
}
117+
118+
// Validate validates the configuration and fills in defaults for missing values
119+
func (c *Config) Validate() error {
120+
// Set defaults for empty values
121+
if c.Collection == "" {
122+
c.Collection = "_goe_migrations"
123+
}
124+
if c.Timeout <= 0 {
125+
c.Timeout = 5 * time.Minute
126+
}
127+
if c.LockTimeout <= 0 {
128+
c.LockTimeout = 30 * time.Minute
129+
}
130+
if c.LockHeartbeat <= 0 {
131+
c.LockHeartbeat = 30 * time.Second
132+
}
133+
if c.VersionScheme != "sequential" && c.VersionScheme != "timestamp" {
134+
c.VersionScheme = "sequential"
135+
}
136+
if c.SchemaVersionField == "" {
137+
c.SchemaVersionField = "_goe_sv"
138+
}
139+
return nil
140+
}

0 commit comments

Comments
 (0)