Welcome to anhgelus's logs. anhgelus.world
standard-site go markdown indie brutalist small-web atproto
1

Configure Feed

Select the types of activity you want to include in your feed.

feat(backend): connect to sqlite db

+94
+1
.gitignore
··· 161 161 data 162 162 small-web 163 163 *.tar.gz 164 + *.sqlite
+2
backend/config.go
··· 35 35 DefaultImage string `toml:"default_image"` 36 36 Quotes []string `toml:"quotes"` 37 37 Language string `toml:"language"` 38 + Database string `toml:"database"` 38 39 39 40 Sections []Section `toml:"section"` 40 41 ··· 73 74 }} 74 75 c.RootFolder = "data" 75 76 c.PublicFolder = "public" 77 + c.Database = "database.sqlite" 76 78 c.Quotes = []string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do."} 77 79 c.Replacers = []Replacer{{"~", " "}} 78 80 }
+73
backend/db.go
··· 1 + package backend 2 + 3 + import ( 4 + "context" 5 + "database/sql" 6 + "embed" 7 + "fmt" 8 + "log/slog" 9 + "regexp" 10 + "slices" 11 + "strconv" 12 + 13 + _ "github.com/mattn/go-sqlite3" 14 + ) 15 + 16 + //go:embed migrations 17 + var migrations embed.FS 18 + 19 + var nameReg = regexp.MustCompile(`(\d{3})_[a-zA-Z_-]+.sql`) 20 + 21 + func ConnectDatabase(cfg *Config) *sql.DB { 22 + db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared", cfg.Database)) 23 + if err != nil { 24 + panic(err) 25 + } 26 + db.SetMaxOpenConns(1) 27 + return db 28 + } 29 + 30 + func RunMigration(ctx context.Context, db *sql.DB) error { 31 + entries, err := migrations.ReadDir("migrations") 32 + if err != nil { 33 + return err 34 + } 35 + type dbConfig struct { 36 + Id int 37 + Migration int 38 + } 39 + type runMig struct { 40 + val string 41 + n int 42 + } 43 + var toRun []runMig 44 + for _, e := range entries { 45 + rawId := nameReg.FindStringSubmatch(e.Name()) 46 + id, err := strconv.Atoi(rawId[1]) 47 + if err != nil { 48 + return err 49 + } 50 + b, err := migrations.ReadFile("migrations/" + e.Name()) 51 + if err != nil { 52 + return err 53 + } 54 + slog.Debug("loading migration", "n", id, "file", e.Name(), "content", string(b)) 55 + toRun = append(toRun, runMig{ 56 + val: string(b), n: id, 57 + }) 58 + } 59 + if len(toRun) == 0 { 60 + return nil 61 + } 62 + slices.SortFunc(toRun, func(a, b runMig) int { 63 + return a.n - b.n 64 + }) 65 + for _, m := range toRun { 66 + slog.Info("migrating", "n", m.n) 67 + _, err := db.ExecContext(ctx, m.val) 68 + if err != nil { 69 + return err 70 + } 71 + } 72 + return nil 73 + }
+4
backend/migrations/000_init.sql
··· 1 + CREATE TABLE IF NOT EXISTS config( 2 + id INTEGER PRIMARY KEY AUTOINCREMENT, 3 + migration INTEGER 4 + );
+2
go.mod
··· 8 8 github.com/joho/godotenv v1.5.1 9 9 github.com/pelletier/go-toml/v2 v2.2.4 10 10 ) 11 + 12 + require github.com/mattn/go-sqlite3 v1.14.32 // indirect
+2
go.sum
··· 4 4 github.com/go-chi/httplog/v3 v3.2.2/go.mod h1:N/J1l5l1fozUrqIVuT8Z/HzNeSy8TF2EFyokPLe6y2w= 5 5 github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 6 6 github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 7 + github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= 8 + github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 7 9 github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= 8 10 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
+10
main.go
··· 12 12 "os/signal" 13 13 "strconv" 14 14 "syscall" 15 + "time" 15 16 16 17 "git.anhgelus.world/anhgelus/small-web/backend" 17 18 "github.com/joho/godotenv" ··· 56 57 if !ok { 57 58 slog.Info("exiting") 58 59 os.Exit(1) 60 + } 61 + 62 + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) 63 + defer cancel() 64 + db := backend.ConnectDatabase(cfg) 65 + defer db.Close() 66 + err := backend.RunMigration(ctx, db) 67 + if err != nil { 68 + panic(err) 59 69 } 60 70 61 71 for _, sec := range cfg.Sections {