···44 "encoding/json"
55 "net/http"
66 "strconv"
77+88+ "github.com/go-chi/chi/v5"
79)
810911func (h *Handler) HandleGetTrendingTags(w http.ResponseWriter, r *http.Request) {
···2325 w.Header().Set("Content-Type", "application/json")
2426 json.NewEncoder(w).Encode(tags)
2527}
2828+2929+func (h *Handler) HandleGetUserTags(w http.ResponseWriter, r *http.Request) {
3030+ did := chi.URLParam(r, "did")
3131+ if did == "" {
3232+ http.Error(w, `{"error": "did is required"}`, http.StatusBadRequest)
3333+ return
3434+ }
3535+3636+ limit := 50
3737+ if l := r.URL.Query().Get("limit"); l != "" {
3838+ if val, err := strconv.Atoi(l); err == nil && val > 0 && val <= 100 {
3939+ limit = val
4040+ }
4141+ }
4242+4343+ tags, err := h.db.GetUserTags(did, limit)
4444+ if err != nil {
4545+ http.Error(w, `{"error": "Failed to fetch user tags"}`, http.StatusInternalServerError)
4646+ return
4747+ }
4848+4949+ w.Header().Set("Content-Type", "application/json")
5050+ json.NewEncoder(w).Encode(tags)
5151+}
+133-37
backend/internal/db/tags.go
···11package db
2233+import "database/sql"
44+35type TrendingTag struct {
46 Tag string `json:"tag"`
57 Count int `json:"count"`
···911 var query string
1012 if db.driver == "postgres" {
1113 query = `
1212- SELECT
1313- value as tag,
1414- COUNT(*) as count
1515- FROM annotations, json_array_elements_text(tags_json::json) as value
1616- WHERE tags_json IS NOT NULL
1717- AND tags_json != ''
1818- AND tags_json != '[]'
1919- AND created_at > NOW() - INTERVAL '7 days'
1414+ SELECT tag, SUM(cnt) as count FROM (
1515+ SELECT value as tag, COUNT(*) as cnt
1616+ FROM annotations, json_array_elements_text(tags_json::json) as value
1717+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
1818+ AND created_at > NOW() - INTERVAL '14 days'
1919+ GROUP BY tag
2020+ UNION ALL
2121+ SELECT value as tag, COUNT(*) as cnt
2222+ FROM highlights, json_array_elements_text(tags_json::json) as value
2323+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
2424+ AND created_at > NOW() - INTERVAL '14 days'
2525+ GROUP BY tag
2626+ UNION ALL
2727+ SELECT value as tag, COUNT(*) as cnt
2828+ FROM bookmarks, json_array_elements_text(tags_json::json) as value
2929+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
3030+ AND created_at > NOW() - INTERVAL '14 days'
3131+ GROUP BY tag
3232+ ) combined
2033 GROUP BY tag
2121- HAVING COUNT(*) > 2
2222- ORDER BY COUNT(*) DESC
3434+ HAVING SUM(cnt) >= 2
3535+ ORDER BY count DESC
2336 LIMIT $1
2437 `
2525- rows, err := db.Query(query, limit)
2626- if err != nil {
3838+ } else {
3939+ query = `
4040+ SELECT tag, SUM(cnt) as count FROM (
4141+ SELECT json_each.value as tag, COUNT(*) as cnt
4242+ FROM annotations, json_each(annotations.tags_json)
4343+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
4444+ AND created_at > datetime('now', '-14 days')
4545+ GROUP BY tag
4646+ UNION ALL
4747+ SELECT json_each.value as tag, COUNT(*) as cnt
4848+ FROM highlights, json_each(highlights.tags_json)
4949+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
5050+ AND created_at > datetime('now', '-14 days')
5151+ GROUP BY tag
5252+ UNION ALL
5353+ SELECT json_each.value as tag, COUNT(*) as cnt
5454+ FROM bookmarks, json_each(bookmarks.tags_json)
5555+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
5656+ AND created_at > datetime('now', '-14 days')
5757+ GROUP BY tag
5858+ ) combined
5959+ GROUP BY tag
6060+ HAVING SUM(cnt) >= 2
6161+ ORDER BY count DESC
6262+ LIMIT ?
6363+ `
6464+ }
6565+6666+ var rows *sql.Rows
6767+ var err error
6868+ if db.driver == "postgres" {
6969+ rows, err = db.Query(query, limit)
7070+ } else {
7171+ rows, err = db.Query(db.Rebind(query), limit)
7272+ }
7373+ if err != nil {
7474+ return nil, err
7575+ }
7676+ defer rows.Close()
7777+7878+ var tags []TrendingTag
7979+ for rows.Next() {
8080+ var t TrendingTag
8181+ if err := rows.Scan(&t.Tag, &t.Count); err != nil {
2782 return nil, err
2883 }
2929- defer rows.Close()
8484+ tags = append(tags, t)
8585+ }
30863131- var tags []TrendingTag
3232- for rows.Next() {
3333- var t TrendingTag
3434- if err := rows.Scan(&t.Tag, &t.Count); err != nil {
3535- return nil, err
3636- }
3737- tags = append(tags, t)
3838- }
3939- return tags, nil
8787+ if err = rows.Err(); err != nil {
8888+ return nil, err
8989+ }
9090+9191+ if tags == nil {
9292+ return []TrendingTag{}, nil
9393+ }
9494+9595+ return tags, nil
9696+}
9797+9898+func (db *DB) GetUserTags(did string, limit int) ([]TrendingTag, error) {
9999+ var query string
100100+ if db.driver == "postgres" {
101101+ query = `
102102+ SELECT tag, SUM(cnt) as count FROM (
103103+ SELECT value as tag, COUNT(*) as cnt
104104+ FROM annotations, json_array_elements_text(tags_json::json) as value
105105+ WHERE author_did = $1 AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
106106+ GROUP BY tag
107107+ UNION ALL
108108+ SELECT value as tag, COUNT(*) as cnt
109109+ FROM highlights, json_array_elements_text(tags_json::json) as value
110110+ WHERE author_did = $1 AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
111111+ GROUP BY tag
112112+ UNION ALL
113113+ SELECT value as tag, COUNT(*) as cnt
114114+ FROM bookmarks, json_array_elements_text(tags_json::json) as value
115115+ WHERE author_did = $1 AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
116116+ GROUP BY tag
117117+ ) combined
118118+ GROUP BY tag
119119+ ORDER BY count DESC
120120+ LIMIT $2
121121+ `
122122+ } else {
123123+ query = `
124124+ SELECT tag, SUM(cnt) as count FROM (
125125+ SELECT json_each.value as tag, COUNT(*) as cnt
126126+ FROM annotations, json_each(annotations.tags_json)
127127+ WHERE author_did = ? AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
128128+ GROUP BY tag
129129+ UNION ALL
130130+ SELECT json_each.value as tag, COUNT(*) as cnt
131131+ FROM highlights, json_each(highlights.tags_json)
132132+ WHERE author_did = ? AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
133133+ GROUP BY tag
134134+ UNION ALL
135135+ SELECT json_each.value as tag, COUNT(*) as cnt
136136+ FROM bookmarks, json_each(bookmarks.tags_json)
137137+ WHERE author_did = ? AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
138138+ GROUP BY tag
139139+ ) combined
140140+ GROUP BY tag
141141+ ORDER BY count DESC
142142+ LIMIT ?
143143+ `
40144 }
411454242- query = `
4343- SELECT
4444- json_each.value as tag,
4545- COUNT(*) as count
4646- FROM annotations, json_each(annotations.tags_json)
4747- WHERE tags_json IS NOT NULL
4848- AND tags_json != ''
4949- AND tags_json != '[]'
5050- AND created_at > datetime('now', '-7 days')
5151- GROUP BY tag
5252- HAVING count > 2
5353- ORDER BY count DESC
5454- LIMIT ?
5555- `
5656- rows, err := db.Query(db.Rebind(query), limit)
146146+ var rows *sql.Rows
147147+ var err error
148148+ if db.driver == "postgres" {
149149+ rows, err = db.Query(query, did, limit)
150150+ } else {
151151+ rows, err = db.Query(db.Rebind(query), did, did, did, limit)
152152+ }
57153 if err != nil {
58154 return nil, err
59155 }