···4 "encoding/json"
5 "net/http"
6 "strconv"
7+8+ "github.com/go-chi/chi/v5"
9)
1011func (h *Handler) HandleGetTrendingTags(w http.ResponseWriter, r *http.Request) {
···25 w.Header().Set("Content-Type", "application/json")
26 json.NewEncoder(w).Encode(tags)
27}
28+29+func (h *Handler) HandleGetUserTags(w http.ResponseWriter, r *http.Request) {
30+ did := chi.URLParam(r, "did")
31+ if did == "" {
32+ http.Error(w, `{"error": "did is required"}`, http.StatusBadRequest)
33+ return
34+ }
35+36+ limit := 50
37+ if l := r.URL.Query().Get("limit"); l != "" {
38+ if val, err := strconv.Atoi(l); err == nil && val > 0 && val <= 100 {
39+ limit = val
40+ }
41+ }
42+43+ tags, err := h.db.GetUserTags(did, limit)
44+ if err != nil {
45+ http.Error(w, `{"error": "Failed to fetch user tags"}`, http.StatusInternalServerError)
46+ return
47+ }
48+49+ w.Header().Set("Content-Type", "application/json")
50+ json.NewEncoder(w).Encode(tags)
51+}
+133-37
backend/internal/db/tags.go
···1package db
2003type TrendingTag struct {
4 Tag string `json:"tag"`
5 Count int `json:"count"`
···9 var query string
10 if db.driver == "postgres" {
11 query = `
12- SELECT
13- value as tag,
14- COUNT(*) as count
15- FROM annotations, json_array_elements_text(tags_json::json) as value
16- WHERE tags_json IS NOT NULL
17- AND tags_json != ''
18- AND tags_json != '[]'
19- AND created_at > NOW() - INTERVAL '7 days'
0000000000020 GROUP BY tag
21- HAVING COUNT(*) > 2
22- ORDER BY COUNT(*) DESC
23 LIMIT $1
24 `
25- rows, err := db.Query(query, limit)
26- if err != nil {
00000000000000000000000000000000000000000027 return nil, err
28 }
29- defer rows.Close()
03031- var tags []TrendingTag
32- for rows.Next() {
33- var t TrendingTag
34- if err := rows.Scan(&t.Tag, &t.Count); err != nil {
35- return nil, err
36- }
37- tags = append(tags, t)
38- }
39- return tags, nil
00000000000000000000000000000000000000000000000040 }
4142- query = `
43- SELECT
44- json_each.value as tag,
45- COUNT(*) as count
46- FROM annotations, json_each(annotations.tags_json)
47- WHERE tags_json IS NOT NULL
48- AND tags_json != ''
49- AND tags_json != '[]'
50- AND created_at > datetime('now', '-7 days')
51- GROUP BY tag
52- HAVING count > 2
53- ORDER BY count DESC
54- LIMIT ?
55- `
56- rows, err := db.Query(db.Rebind(query), limit)
57 if err != nil {
58 return nil, err
59 }
···1package db
23+import "database/sql"
4+5type TrendingTag struct {
6 Tag string `json:"tag"`
7 Count int `json:"count"`
···11 var query string
12 if db.driver == "postgres" {
13 query = `
14+ SELECT tag, SUM(cnt) as count FROM (
15+ SELECT value as tag, COUNT(*) as cnt
16+ FROM annotations, json_array_elements_text(tags_json::json) as value
17+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
18+ AND created_at > NOW() - INTERVAL '14 days'
19+ GROUP BY tag
20+ UNION ALL
21+ SELECT value as tag, COUNT(*) as cnt
22+ FROM highlights, json_array_elements_text(tags_json::json) as value
23+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
24+ AND created_at > NOW() - INTERVAL '14 days'
25+ GROUP BY tag
26+ UNION ALL
27+ SELECT value as tag, COUNT(*) as cnt
28+ FROM bookmarks, json_array_elements_text(tags_json::json) as value
29+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
30+ AND created_at > NOW() - INTERVAL '14 days'
31+ GROUP BY tag
32+ ) combined
33 GROUP BY tag
34+ HAVING SUM(cnt) >= 2
35+ ORDER BY count DESC
36 LIMIT $1
37 `
38+ } else {
39+ query = `
40+ SELECT tag, SUM(cnt) as count FROM (
41+ SELECT json_each.value as tag, COUNT(*) as cnt
42+ FROM annotations, json_each(annotations.tags_json)
43+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
44+ AND created_at > datetime('now', '-14 days')
45+ GROUP BY tag
46+ UNION ALL
47+ SELECT json_each.value as tag, COUNT(*) as cnt
48+ FROM highlights, json_each(highlights.tags_json)
49+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
50+ AND created_at > datetime('now', '-14 days')
51+ GROUP BY tag
52+ UNION ALL
53+ SELECT json_each.value as tag, COUNT(*) as cnt
54+ FROM bookmarks, json_each(bookmarks.tags_json)
55+ WHERE tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
56+ AND created_at > datetime('now', '-14 days')
57+ GROUP BY tag
58+ ) combined
59+ GROUP BY tag
60+ HAVING SUM(cnt) >= 2
61+ ORDER BY count DESC
62+ LIMIT ?
63+ `
64+ }
65+66+ var rows *sql.Rows
67+ var err error
68+ if db.driver == "postgres" {
69+ rows, err = db.Query(query, limit)
70+ } else {
71+ rows, err = db.Query(db.Rebind(query), limit)
72+ }
73+ if err != nil {
74+ return nil, err
75+ }
76+ defer rows.Close()
77+78+ var tags []TrendingTag
79+ for rows.Next() {
80+ var t TrendingTag
81+ if err := rows.Scan(&t.Tag, &t.Count); err != nil {
82 return nil, err
83 }
84+ tags = append(tags, t)
85+ }
8687+ if err = rows.Err(); err != nil {
88+ return nil, err
89+ }
90+91+ if tags == nil {
92+ return []TrendingTag{}, nil
93+ }
94+95+ return tags, nil
96+}
97+98+func (db *DB) GetUserTags(did string, limit int) ([]TrendingTag, error) {
99+ var query string
100+ if db.driver == "postgres" {
101+ query = `
102+ SELECT tag, SUM(cnt) as count FROM (
103+ SELECT value as tag, COUNT(*) as cnt
104+ FROM annotations, json_array_elements_text(tags_json::json) as value
105+ WHERE author_did = $1 AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
106+ GROUP BY tag
107+ UNION ALL
108+ SELECT value as tag, COUNT(*) as cnt
109+ FROM highlights, json_array_elements_text(tags_json::json) as value
110+ WHERE author_did = $1 AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
111+ GROUP BY tag
112+ UNION ALL
113+ SELECT value as tag, COUNT(*) as cnt
114+ FROM bookmarks, json_array_elements_text(tags_json::json) as value
115+ WHERE author_did = $1 AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
116+ GROUP BY tag
117+ ) combined
118+ GROUP BY tag
119+ ORDER BY count DESC
120+ LIMIT $2
121+ `
122+ } else {
123+ query = `
124+ SELECT tag, SUM(cnt) as count FROM (
125+ SELECT json_each.value as tag, COUNT(*) as cnt
126+ FROM annotations, json_each(annotations.tags_json)
127+ WHERE author_did = ? AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
128+ GROUP BY tag
129+ UNION ALL
130+ SELECT json_each.value as tag, COUNT(*) as cnt
131+ FROM highlights, json_each(highlights.tags_json)
132+ WHERE author_did = ? AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
133+ GROUP BY tag
134+ UNION ALL
135+ SELECT json_each.value as tag, COUNT(*) as cnt
136+ FROM bookmarks, json_each(bookmarks.tags_json)
137+ WHERE author_did = ? AND tags_json IS NOT NULL AND tags_json != '' AND tags_json != '[]'
138+ GROUP BY tag
139+ ) combined
140+ GROUP BY tag
141+ ORDER BY count DESC
142+ LIMIT ?
143+ `
144 }
145146+ var rows *sql.Rows
147+ var err error
148+ if db.driver == "postgres" {
149+ rows, err = db.Query(query, did, limit)
150+ } else {
151+ rows, err = db.Query(db.Rebind(query), did, did, did, limit)
152+ }
00000000153 if err != nil {
154 return nil, err
155 }