contrib/migrate-db: new script

This utility will migrate data between any two soju databases.
Sqlite to postgres or postgres to sqlite.
This commit is contained in:
gildarts 2022-06-22 13:48:54 -04:00 committed by Simon Ser
parent e2e3e2731b
commit 7ba3cba1e6
1 changed files with 158 additions and 0 deletions

158
contrib/migrate-db/main.go Normal file
View File

@ -0,0 +1,158 @@
package main
import (
"context"
"flag"
"fmt"
"log"
"strings"
"git.sr.ht/~emersion/soju/database"
)
const usage = `usage: migrate-db <source database> <destination database>
Migrates an existing Soju database to another system. Database is specified
in the format of "driver:source" where driver is sqlite3 or postgres and source
is the string that would be in the Soju config file.
Options:
-help Show this help message
`
func init() {
flag.Usage = func() {
fmt.Fprint(flag.CommandLine.Output(), usage)
}
}
func main() {
flag.Parse()
ctx := context.Background()
source := strings.Split(flag.Arg(0), ":")
destination := strings.Split(flag.Arg(1), ":")
if len(source) != 2 || len(destination) != 2 {
log.Fatalf("source or destination not properly specified: %s %s", flag.Arg(0), flag.Arg(1))
}
sourcedb, err := database.Open(source[0], source[1])
if err != nil {
log.Fatalf("failed to open database: %v", err)
}
defer sourcedb.Close()
destinationdb, err := database.Open(destination[0], destination[1])
if err != nil {
log.Fatalf("failed to open database: %v", err)
}
defer destinationdb.Close()
users, err := sourcedb.ListUsers(ctx)
if err != nil {
log.Fatal("unable to get source users")
}
for _, user := range users {
log.Printf("Storing user: %s\n", user.Username)
user.ID = 0
err := destinationdb.StoreUser(ctx, &user)
if err != nil {
log.Fatalf("unable to store user: #%d %s", user.ID, user.Username)
}
networks, err := sourcedb.ListNetworks(ctx, user.ID)
if err != nil {
log.Fatalf("unable to get source networks for user: #%d %s", user.ID, user.Username)
}
for _, network := range networks {
log.Printf("Storing network: %s\n", network.Name)
network.ID = 0
err := destinationdb.StoreNetwork(ctx, user.ID, &network)
if err != nil {
log.Fatalf("unable to store network: #%d %s", network.ID, network.Name)
}
channels, err := sourcedb.ListChannels(ctx, network.ID)
if err != nil {
log.Fatalf("unable to get source channels for network: #%d %s", network.ID, network.Name)
}
for _, channel := range channels {
log.Printf("Storing channel: %s\n", channel.Name)
channel.ID = 0
err := destinationdb.StoreChannel(ctx, network.ID, &channel)
if err != nil {
log.Fatalf("unable to store channel: #%d %s", channel.ID, channel.Name)
}
}
deliveryReceipts, err := sourcedb.ListDeliveryReceipts(ctx, network.ID)
if err != nil {
log.Fatalf("unable to get source delivery receipts for network: #%d %s", network.ID, network.Name)
}
drcpts := make(map[string][]database.DeliveryReceipt)
for _, d := range deliveryReceipts {
if drcpts[d.Client] == nil {
drcpts[d.Client] = make([]database.DeliveryReceipt, 0)
}
d.ID = 0
drcpts[d.Client] = append(drcpts[d.Client], d)
}
for client, rcpts := range drcpts {
log.Printf("Storing delivery receipt for: %s.%s.%s", user.Username, network.Name, client)
err := destinationdb.StoreClientDeliveryReceipts(ctx, network.ID, client, rcpts)
if err != nil {
log.Fatalf("unable to store delivery receipts for network and client: %s %s", network.Name, client)
}
}
// TODO: migrate read receipts as well
webPushSubscriptions, err := sourcedb.ListWebPushSubscriptions(ctx, user.ID, network.ID)
if err != nil {
log.Fatalf("unable to get source web push subscriptions for user and network: %s %s", user.Username, network.Name)
}
for _, sub := range webPushSubscriptions {
log.Printf("Storing web push subscription: %s.%s.%d", user.Username, network.Name, sub.ID)
sub.ID = 0
err := destinationdb.StoreWebPushSubscription(ctx, user.ID, network.ID, &sub)
if err != nil {
log.Fatalf("unable to store web push subscription for user and network: %s %s", user.Username, network.Name)
}
}
}
}
webPushConfigs, err := sourcedb.ListWebPushConfigs(ctx)
if err != nil {
log.Fatal("unable to get source web push configs")
}
for _, config := range webPushConfigs {
log.Printf("Storing web push config: %d", config.ID)
config.ID = 0
err := destinationdb.StoreWebPushConfig(ctx, &config)
if err != nil {
log.Fatalf("unable to store web push config: #%d", config.ID)
}
}
}