diff options
| author | Anhgelus Morhtuuzh <william@herges.fr> | 2026-03-08 13:38:10 +0100 |
|---|---|---|
| committer | Anhgelus Morhtuuzh <william@herges.fr> | 2026-03-08 13:38:10 +0100 |
| commit | ddd6306752186c149f8ad3bf2f59b5428cf01296 (patch) | |
| tree | 0e40562ef636a9a76cc298e8695cc04abbdcfda5 /common | |
| parent | 88e1b886e5471552c055374f71d848d3a3dcb4b6 (diff) | |
feat(db): run migrations
Diffstat (limited to 'common')
| -rw-r--r-- | common/db.go | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/common/db.go b/common/db.go new file mode 100644 index 0000000..76e39a2 --- /dev/null +++ b/common/db.go @@ -0,0 +1,57 @@ +package common + +import ( + "context" + "database/sql" + "embed" + "fmt" + "log/slog" + "path" + "regexp" + "strconv" + "strings" + + "github.com/nyttikord/avl" +) + +var regexpMigration = regexp.MustCompile(`(\d{3})-(.*)\.sql`) + +type migrationData struct { + id uint64 + name string + content string +} + +func Migrate(ctx context.Context, log *slog.Logger, db *sql.DB, migrations embed.FS, dir string) error { + entries, err := migrations.ReadDir(dir) + if err != nil { + return err + } + tree := avl.NewKeySimple[uint64, migrationData]() + for _, entry := range entries { + if strings.HasSuffix(entry.Name(), ".sql") { + log.Debug("reading migration...", "path", dir+"/"+entry.Name()) + subs := regexpMigration.FindStringSubmatch(entry.Name()) + if len(subs) < 3 { + return fmt.Errorf("invalid migration name %s", entry.Name()) + } + id, _ := strconv.ParseUint(subs[1], 10, 16) + b, err := migrations.ReadFile(path.Join(dir, entry.Name())) + if err != nil { + return err + } + tree.Insert(id, migrationData{id, subs[2], string(b)}) + } else { + log.Warn("invalid migration entry, skipping", "path", dir+"/"+entry.Name()) + } + } + for _, mig := range tree.Sort() { + log.Debug("migrating...", "id", mig.id, "name", mig.name) + _, err := db.ExecContext(ctx, mig.content) + if err != nil { + log.Error("migrating", "id", mig.id, "name", mig.name) + return err + } + } + return nil +} |
