diff --git a/migrations/000008_add_serial_n_to_garbages.down.sql b/migrations/000008_add_serial_n_to_garbages.down.sql
new file mode 100644
index 0000000..1bfb275
--- /dev/null
+++ b/migrations/000008_add_serial_n_to_garbages.down.sql
@@ -0,0 +1 @@
+ALTER TABLE garbages DROP COLUMN n;
diff --git a/migrations/000008_add_serial_n_to_garbages.up.sql b/migrations/000008_add_serial_n_to_garbages.up.sql
new file mode 100644
index 0000000..029d395
--- /dev/null
+++ b/migrations/000008_add_serial_n_to_garbages.up.sql
@@ -0,0 +1 @@
+ALTER TABLE garbages ADD COLUMN n BIGSERIAL NOT NULL;
diff --git a/partials/garbage/list.html b/partials/garbage/list.html
index a367b74..f1e8ebc 100644
--- a/partials/garbage/list.html
+++ b/partials/garbage/list.html
@@ -4,6 +4,16 @@
{{end}}
+
+
{{- with .Alert -}}
{{ . }}
{{ end }}
diff --git a/server.go b/server.go
index 5a39725..96ebc0e 100644
--- a/server.go
+++ b/server.go
@@ -50,6 +50,7 @@ type Garbage struct {
Metadata map[string]any
Url string
CreatedAt time.Time
+ N int
}
// User represents 'user' records from the database
@@ -85,6 +86,7 @@ var db *pgxpool.Pool
var sessions *scs.SessionManager
var sessionStore *pgxstore.PostgresStore
var NQ types.Backend
+var pageSize = 25
// run migrations, acquire a database connection pool, and create the session store
func init() {
@@ -676,19 +678,46 @@ func argsfn(kvs ...interface{}) (map[string]interface{}, error) {
return m, nil
}
+// pagedQuery returns a paged query for the given query
+func pagedQuery(r *http.Request, query string) (pagedQuery string, firstItem *int) {
+ firstItemStr := r.URL.Query().Get("first_item")
+
+ var err error
+ var fi int
+ fi, err = strconv.Atoi(firstItemStr)
+ if err != nil {
+ pagedQuery = query + " ORDER BY n DESC LIMIT $1"
+ return
+ }
+ firstItem = &fi
+
+ // newer items have a larger n, since n monotonically increases
+ // hence we filter where n < our first item's n
+ pagedQuery = query + " WHERE n < $2"
+ pagedQuery = pagedQuery + " ORDER BY n DESC LIMIT $1"
+
+ return
+}
+
// listGarbageHandler returns the latest garbage
func listGarbageHandler(w http.ResponseWriter, r *http.Request) {
userID := sessions.GetString(r.Context(), "userID")
+
+ query := `SELECT
+ garbages.id, n, owner_id, username, title, content, metadata, url, garbages.created_at
+ FROM garbages
+ JOIN users ON garbages.owner_id = users.id`
+ pagedQuery, firstItem := pagedQuery(r, query)
+
ctx := context.Background()
garbage := []*Garbage{}
- err := pgxscan.Select(
- ctx,
- db,
- &garbage,
- `SELECT garbages.id, owner_id, username, title, content, metadata, url, garbages.created_at
- FROM garbages
- JOIN users ON garbages.owner_id = users.id
- ORDER BY created_at DESC`)
+ var err error
+ if firstItem != nil {
+ err = pgxscan.Select(ctx, db, &garbage, pagedQuery, pageSize, firstItem)
+ } else {
+ err = pgxscan.Select(ctx, db, &garbage, pagedQuery, pageSize)
+ }
+
if err != nil {
ise(err, w)
return
@@ -699,23 +728,44 @@ func listGarbageHandler(w http.ResponseWriter, r *http.Request) {
Funcs(template.FuncMap{"argsfn": argsfn}).
ParseFS(partialsFS, "partials/garbage/list.html", "partials/garbage/*.tmpl"))
- err = tmpl.ExecuteTemplate(w, "list.html", map[string]any{
+ // pagination
+ var lastItem *int
+ il := len(garbage) - 1
+ if il >= 0 {
+ lastItem = &(garbage[il].N)
+ }
+
+ var buff = bytes.NewBufferString("")
+ err = tmpl.ExecuteTemplate(buff, "list.html", map[string]any{
"Posts": garbage,
"ApiBaseUrl": apiURL(),
"LoggedIn": isLoggedIn(r),
"UserID": userID,
+ "LastItem": lastItem,
})
if err != nil {
ise(err, w)
return
}
+ if isPartialRequest(r) {
+ w.Write(buff.Bytes())
+ } else {
+ indexFile, _ := publicFS.Open("public/index.html")
+ content := html_parser.ParseAndSplice(indexFile, "content", buff.String())
+ log.Println(content)
+ w.Write([]byte(content))
+ }
+
w.WriteHeader(http.StatusOK)
}
+func isPartialRequest(r *http.Request) bool {
+ return r.Header.Get("hx-request") != ""
+}
+
// showGarbageHandler returns the latest garbage
func showGarbageHandler(w http.ResponseWriter, r *http.Request) {
- isPartialRequest := r.Header.Get("hx-request") != ""
garbageID := chi.URLParam(r, "garbage_id")
userID := sessions.GetString(r.Context(), "userID")
ctx := context.Background()
@@ -727,8 +777,7 @@ func showGarbageHandler(w http.ResponseWriter, r *http.Request) {
`SELECT garbages.id, owner_id, username, title, content, metadata, url, garbages.created_at
FROM garbages
JOIN users ON garbages.owner_id = users.id
- WHERE garbages.id = $1
- ORDER BY created_at DESC`, garbageID)
+ WHERE garbages.id = $1`, garbageID)
if err != nil {
ise(err, w)
return
@@ -750,7 +799,7 @@ func showGarbageHandler(w http.ResponseWriter, r *http.Request) {
return
}
- if isPartialRequest {
+ if isPartialRequest(r) {
w.Write(buff.Bytes())
} else {
indexFile, _ := publicFS.Open("public/index.html")