// Command dumpschema regenerates docs/DATABASE.md from the real, live // database schema -- it opens a fresh temp database through store.Open // (the exact same code path geniusrund itself uses) and introspects // sqlite_master, so the generated documentation can never drift from what // the app actually creates. Run it after any change to // internal/store/schema.sql: // // go run ./cmd/dumpschema package main import ( "fmt" "log" "os" "path/filepath" "strings" "geniusrun/backend/internal/store" ) type schemaEntry struct { typ string // "table" or "view" name string tblName string sql string } func main() { tmpDir, err := os.MkdirTemp("", "geniusrun-dumpschema") must(err) defer os.RemoveAll(tmpDir) db, err := store.Open(filepath.Join(tmpDir, "schema-check.db")) must(err) defer db.Close() rows, err := db.Query(` SELECT type, name, tbl_name, sql FROM sqlite_master WHERE sql IS NOT NULL AND name NOT LIKE 'sqlite_%' ORDER BY rowid`) must(err) defer rows.Close() var tables, views []schemaEntry indexesByTable := map[string][]schemaEntry{} for rows.Next() { var e schemaEntry must(rows.Scan(&e.typ, &e.name, &e.tblName, &e.sql)) switch e.typ { case "table": tables = append(tables, e) case "view": views = append(views, e) case "index": indexesByTable[e.tblName] = append(indexesByTable[e.tblName], e) } } must(rows.Err()) var b strings.Builder b.WriteString("# geniusrun database schema\n\n") b.WriteString("Generated from the live schema via `go run ./cmd/dumpschema` -- do not hand-edit. ") b.WriteString("The source of truth is `backend/internal/store/schema.sql`; regenerate this file after changing it.\n\n") b.WriteString("## Tables\n\n") for _, t := range tables { fmt.Fprintf(&b, "- [`%s`](#%s)\n", t.name, t.name) } b.WriteString("\n") for _, t := range tables { fmt.Fprintf(&b, "## `%s`\n\n", t.name) fmt.Fprintf(&b, "```sql\n%s;\n```\n\n", t.sql) if idxs := indexesByTable[t.name]; len(idxs) > 0 { b.WriteString("Indexes:\n\n```sql\n") for _, idx := range idxs { fmt.Fprintf(&b, "%s;\n", idx.sql) } b.WriteString("```\n\n") } } if len(views) > 0 { b.WriteString("## Views\n\n") for _, v := range views { fmt.Fprintf(&b, "### `%s`\n\n", v.name) fmt.Fprintf(&b, "```sql\n%s;\n```\n\n", v.sql) } } outPath := "../docs/DATABASE.md" must(os.WriteFile(outPath, []byte(b.String()), 0644)) log.Printf("wrote %s", outPath) } func must(err error) { if err != nil { log.Fatal(err) } }