From f1ee076bcba5508b7558552aaee74ff4d6d49f41 Mon Sep 17 00:00:00 2001 From: Kristian Borgwarth <10348902@pm.me> Date: Fri, 20 Mar 2026 00:11:05 +0100 Subject: [PATCH] feat(database): migration setup --- app/main.go | 0 cmd/main.go | 28 +++++++ go.mod | 12 +++ go.sum | 21 ++++++ persistence/db_migrator.go | 70 ++++++++++++++++++ persistence/index.db | Bin 0 -> 57344 bytes persistence/index.go | 0 .../migrations/001_dendrite_db_init.sql | 21 ++++++ persistence/migrations/002_tags.sql | 12 +++ persistence/repository/note_repository.go | 0 10 files changed, 164 insertions(+) delete mode 100644 app/main.go create mode 100644 cmd/main.go create mode 100644 persistence/db_migrator.go create mode 100644 persistence/index.db delete mode 100644 persistence/index.go create mode 100644 persistence/migrations/001_dendrite_db_init.sql create mode 100644 persistence/migrations/002_tags.sql delete mode 100644 persistence/repository/note_repository.go diff --git a/app/main.go b/app/main.go deleted file mode 100644 index e69de29..0000000 diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..33b8a1c --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,28 @@ +package main + +import ( + "database/sql" + "log" + "path/filepath" + + migrate "github.com/KristianJBorgwarth/dendrite.daemon/persistence" + _ "modernc.org/sqlite" +) + +func main() { + dbPath := filepath.Join("persistence", "index.db") + + db, err := sql.Open("sqlite", dbPath) + if err != nil { + log.Fatal(err) + } + defer db.Close() + + migrationsDir := filepath.Join("persistence", "migrations") + + if err := migrate.Run(db, migrationsDir); err != nil { + log.Fatal(err) + } + + log.Println("migrations applied successfully") +} diff --git a/go.mod b/go.mod index 176ad5e..ceb31eb 100644 --- a/go.mod +++ b/go.mod @@ -2,3 +2,15 @@ module github.com/KristianJBorgwarth/dendrite.daemon go 1.26 +require ( + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ncruces/go-strftime v1.0.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + golang.org/x/sys v0.42.0 // indirect + modernc.org/libc v1.70.0 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.47.0 // indirect +) diff --git a/go.sum b/go.sum index e69de29..988cc37 100644 --- a/go.sum +++ b/go.sum @@ -0,0 +1,21 @@ +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw= +modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/sqlite v1.47.0 h1:R1XyaNpoW4Et9yly+I2EeX7pBza/w+pmYee/0HJDyKk= +modernc.org/sqlite v1.47.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig= diff --git a/persistence/db_migrator.go b/persistence/db_migrator.go new file mode 100644 index 0000000..867d049 --- /dev/null +++ b/persistence/db_migrator.go @@ -0,0 +1,70 @@ +// Package migrate handles database schema migrations +package migrate + +import ( + "database/sql" + "os" + "path/filepath" + "sort" +) + +func Run(db *sql.DB, dir string) error { + _, err := db.Exec(`CREATE TABLE IF NOT EXISTS schema_migrations (version TEXT PRIMARY KEY);`) + if err != nil { + return err + } + + entries, err := os.ReadDir(dir) + if err != nil { + return err + } + + sort.Slice(entries, func(i, j int) bool { + return entries[i].Name() < entries[j].Name() + }) + + for _, e := range entries { + if e.IsDir(){ + continue + } + + name := e.Name() + + applied, err := isMigrationApplied(db, name) + if err != nil { + return err + } + + if applied { + continue + } + + path := filepath.Join(dir, name) + + sqlBytes, err := os.ReadFile(path) + if err != nil { + return err + } + + if _, err := db.Exec(string(sqlBytes)); err != nil { + return err + } + + if _, err := db.Exec(`INSERT INTO schema_migrations (version) VALUES (?)`, name); err != nil { + return err + } + } + + return nil +} + +func isMigrationApplied(db *sql.DB, version string) (bool, error) { + var v string + err := db.QueryRow(`SELECT version FROM schema_migrations WHERE version= ?`, version).Scan(&v) + + if err == sql.ErrNoRows { + return false, nil + } + + return err == nil, err +} diff --git a/persistence/index.db b/persistence/index.db new file mode 100644 index 0000000000000000000000000000000000000000..d7c18747a6ad181a2c855c88ce34582ed916b437 GIT binary patch literal 57344 zcmeI(&u-f`9KdnON##WT*Bt@@+acT`m^Bnl-0e05nCGa4QO{W%2WwA)TB)fp|7k2` zD|RW8p7$~X_9X2i>=}juyG*1KM~W+K*9u<&k|m0y$q#>mL(@4v8ia8mUd$I$FBV^E zcQswtz7;~#G&9+o$$q_UBq!_F7s;!hIWIajwfn#Q(`fyzHOxz`HE8|O{Id0V^RLEs z{eAtS{&ns5dd#m1TKE9SFP=B{cSJyo=t+;JPzF0JB^kn zjo!%VjvX=Xem8K$GFh}ukzR$q=nu!vBWH9kNlMDP`IH|<{qMV@r{b~mRJ2w3(7$(; z&z40V9*&&;qoK@jecu)%=bbGvx@?zz&k zGaoK&+MR}BIorAx&ivqYbT&!;7I(e#c&@J9WnbOS^0fJ*S+%yd^ovgvm#kdwwH%U6 zQ9d^iBBLN1J@cl47&}kK;$+xAI&n<N$NJ+bMMq5hW$lu4NuyyIV1=lii}`uhisrR+83|&k;GF*BZ%QX}#B4e3`+3wf)Va`M+HMPk!{z zh5!NxAbfBDCl9wLAM0tg_000IagfB*srAi(-RF@OL92q1s} z0tg_000IagfI#^LnE#i5jOif)2q1s}0tg_000IagfB*u_|A_$v5I_I{1Q0*~0R#|0 z009KbFTnr*mw$}uAp!^>fB*srAb