From 4b497a8185c293dd2a50765b286dd39aedd11a0b Mon Sep 17 00:00:00 2001 From: nate smith Date: Tue, 30 Apr 2024 21:19:57 -0700 Subject: [PATCH] support partitioned tables in frontend --- templates/index.tmpl | 19 +++++++- web/web.go | 103 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 109 insertions(+), 13 deletions(-) diff --git a/templates/index.tmpl b/templates/index.tmpl index db50b74..a7d5cd3 100644 --- a/templates/index.tmpl +++ b/templates/index.tmpl @@ -122,10 +122,27 @@ a {

- HELLO. THIS IS A SOFT WARE FOR MAKING CUT-UP POETRY. THERE ARE 467,014,991 POSSIBLE LINES YOU MAY SEE. ALL OF THE LINES ARE FROM THE ENGLISH CORPUS OF PROJECT GUTERNBERG. SOME MAY BE OBJECTIONABLE AND I'M SORRY. THE AUTHOR OF THIS SOFT WARE IS ~VILMIBM. +

+ HELLO. THIS IS A SOFT WARE FOR MAKING CUT-UP POETRY. THERE ARE A VARIETY OF CORPORA TO CHOOSE FROM: +
+ + +
+ THE AUTHOR OF THIS SOFT WARE IS ~VILMIBM. +

+
+ + +
diff --git a/web/web.go b/web/web.go index aaa0c09..97e88bf 100644 --- a/web/web.go +++ b/web/web.go @@ -3,6 +3,7 @@ package web import ( "context" "crypto/rand" + "fmt" "html/template" "log" "math/big" @@ -26,6 +27,12 @@ type phrase struct { Source source } +type corpus struct { + ID string + Name string + MaxID *big.Int +} + func Serve() error { r := gin.Default() r.SetFuncMap(template.FuncMap{ @@ -39,8 +46,65 @@ func Serve() error { r.StaticFile("/main.js", "./web/assets/main.js") r.StaticFile("/html2canvas.min.js", "./web/assets/html2canvas.min.js") - // TODO use new db functions for id ranges - randMax := big.NewInt(db.MaxID) + bctx := context.Background() + + pool, err := db.Pool() + if err != nil { + return fmt.Errorf("db pool failed: %w", err) + } + defer pool.Close() + + corpora := []corpus{} + + conn, err := db.Connect() + if err != nil { + return err + } + + fmt.Println("gathering max IDs...") + rows, err := conn.Query(bctx, "SELECT tablename FROM pg_tables WHERE tablename LIKE '%phrases_%'") + if err != nil { + return fmt.Errorf("tablename query failed: %w", err) + } + defer rows.Close() + tables := []string{} + for rows.Next() { + var tablename string + err = rows.Scan(&tablename) + if err != nil { + return err + } + tables = append(tables, tablename) + } + rows.Close() + + fmt.Printf("found %d tables\n", len(tables)) + + for _, tablename := range tables { + fmt.Printf("- %s...", tablename) + var maxID int64 + err = conn.QueryRow(bctx, fmt.Sprintf("SELECT max(id) FROM %s", tablename)).Scan(&maxID) + if err != nil { + return err + } + fmt.Printf("%v...", maxID) + + parts := strings.Split(tablename, "_") + corpusid := parts[1] + var name string + err := conn.QueryRow(bctx, "SELECT name FROM corpora WHERE id=$1", corpusid).Scan(&name) + if err != nil { + return err + } + fmt.Printf("%s.\n", name) + corpora = append(corpora, corpus{ + ID: corpusid, + Name: name, + MaxID: big.NewInt(maxID), + }) + } + conn.Close(bctx) + fmt.Println("...done") r.HEAD("/", func(c *gin.Context) { c.String(http.StatusOK, "") @@ -48,39 +112,54 @@ func Serve() error { r.GET("/", func(c *gin.Context) { c.HTML(http.StatusOK, "index.tmpl", struct { - // TODO handle multiple corpora - MaxID int - }{db.MaxID}) + Corpora []corpus + }{corpora}) }) - // TODO retool this for pg - r.GET("/line", func(c *gin.Context) { - conn, err := db.Connect() + conn, err := pool.Acquire(bctx) if err != nil { log.Println(err.Error()) c.String(http.StatusInternalServerError, "oh no.") return } - defer conn.Close(context.Background()) + defer conn.Release() - id, err := rand.Int(rand.Reader, randMax) + corpusid := c.DefaultQuery("corpus", "c3d8e9") + + var cpus corpus + + var tablename string + for _, corpus := range corpora { + if corpus.ID == corpusid { + cpus = corpus + tablename = fmt.Sprintf("phrases_%s", corpusid) + } + } + if tablename == "" { + c.String(http.StatusTeapot, "have some tea :)") + } + + id, err := rand.Int(rand.Reader, cpus.MaxID) if err != nil { log.Println(err.Error()) c.String(http.StatusInternalServerError, "oh no.") return } - row := conn.QueryRow(context.Background(), "select p.phrase, s.id, s.name from phrases p join sources s on p.sourceid = s.id where p.id = $1", id.Int64()) var p phrase var s source - err = row.Scan(&p.Text, &s.ID, &s.Name) + err = conn.QueryRow(bctx, + fmt.Sprintf( + "SELECT p.phrase, s.id, s.name FROM phrases_%s p join sources s on p.sourceid = s.id where p.id = $1", cpus.ID), + id.Int64()).Scan(&p.Text, &s.ID, &s.Name) if err != nil { log.Println(err.Error()) c.String(http.StatusInternalServerError, "oh no.") } p.Source = s p.ID = id.Int64() + conn.Release() c.JSON(http.StatusOK, p) })