From 3891a2c23911bdea219cc0531a0cde339ce87411 Mon Sep 17 00:00:00 2001 From: mrhid6 Date: Fri, 24 Jul 2026 13:59:04 +0100 Subject: [PATCH] feat(server): add rename-rollback command for migration 0004 --- server/cmd/rename-rollback/main.go | 78 ++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 server/cmd/rename-rollback/main.go diff --git a/server/cmd/rename-rollback/main.go b/server/cmd/rename-rollback/main.go new file mode 100644 index 0000000..bb8dee8 --- /dev/null +++ b/server/cmd/rename-rollback/main.go @@ -0,0 +1,78 @@ +// Command rename-rollback reverses migration 0004. +// +// Run it only as part of a decision to revert the release that introduced the +// instance rename. It renames instance_id back to org_id and restores the two +// collection names. Like the migration, it only renames — it deletes no +// documents. +// +// rename-rollback -uri mongodb://host:27017 -db vantage -confirm +package main + +import ( + "context" + "flag" + "log" + "time" + + "github.com/mrhid6/vantage/server/internal/services" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" +) + +func main() { + uri := flag.String("uri", "mongodb://localhost:27017", "MongoDB URI") + dbName := flag.String("db", "vantage", "database name") + confirm := flag.Bool("confirm", false, "required; refuses to run without it") + flag.Parse() + + if !*confirm { + log.Fatal("refusing to run without -confirm") + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + defer cancel() + + client, err := mongo.Connect(options.Client().ApplyURI(*uri)) + if err != nil { + log.Fatalf("connect: %v", err) + } + defer client.Disconnect(ctx) + + db := client.Database(*dbName) + + for _, c := range services.ScopedCollections { + res, err := db.Collection(c).UpdateMany(ctx, + bson.M{"instance_id": bson.M{"$exists": true}}, + bson.M{"$rename": bson.M{"instance_id": "org_id"}}, + ) + if err != nil { + log.Fatalf("rename instance_id in %s: %v", c, err) + } + if res.ModifiedCount > 0 { + log.Printf("%s: reverted %d document(s)", c, res.ModifiedCount) + } + } + + for _, r := range []struct{ from, to string }{ + {"instances", "orgs"}, + {"instance_oidc", "org_oidc"}, + } { + cmd := bson.D{ + {Key: "renameCollection", Value: *dbName + "." + r.from}, + {Key: "to", Value: *dbName + "." + r.to}, + } + if err := client.Database("admin").RunCommand(ctx, cmd).Err(); err != nil { + log.Printf("rename %s to %s: %v (continuing)", r.from, r.to, err) + continue + } + log.Printf("renamed collection %s to %s", r.from, r.to) + } + + // Remove the marker so a redeployed new binary re-runs the migration. + if _, err := db.Collection("migrations").DeleteOne(ctx, bson.M{"_id": "0004_org_to_instance"}); err != nil { + log.Printf("clear migration marker: %v", err) + } + + log.Println("rollback complete") +}