this repo has no description
1package db
2
3import (
4 "database/sql"
5 "fmt"
6 "maps"
7 "slices"
8 "sort"
9 "strings"
10 "time"
11
12 "github.com/bluesky-social/indigo/atproto/syntax"
13 "tangled.org/core/appview/models"
14 "tangled.org/core/orm"
15)
16
17func PutComment(tx *sql.Tx, c *models.Comment) error {
18 result, err := tx.Exec(
19 `insert into comments (
20 did,
21 rkey,
22 subject_at,
23 reply_to,
24 body,
25 pull_submission_id,
26 created
27 )
28 values (?, ?, ?, ?, ?, ?, ?)
29 on conflict(did, rkey) do update set
30 subject_at = excluded.subject_at,
31 reply_to = excluded.reply_to,
32 body = excluded.body,
33 edited = case
34 when
35 comments.subject_at != excluded.subject_at
36 or comments.body != excluded.body
37 or comments.reply_to != excluded.reply_to
38 then ?
39 else comments.edited
40 end`,
41 c.Did,
42 c.Rkey,
43 c.Subject,
44 c.ReplyTo,
45 c.Body,
46 c.PullSubmissionId,
47 c.Created.Format(time.RFC3339),
48 time.Now().Format(time.RFC3339),
49 )
50 if err != nil {
51 return err
52 }
53
54 c.Id, err = result.LastInsertId()
55 if err != nil {
56 return err
57 }
58
59 if err := putReferences(tx, c.AtUri(), c.References); err != nil {
60 return fmt.Errorf("put reference_links: %w", err)
61 }
62
63 return nil
64}
65
66func DeleteComments(e Execer, filters ...orm.Filter) error {
67 var conditions []string
68 var args []any
69 for _, filter := range filters {
70 conditions = append(conditions, filter.Condition())
71 args = append(args, filter.Arg()...)
72 }
73
74 whereClause := ""
75 if conditions != nil {
76 whereClause = " where " + strings.Join(conditions, " and ")
77 }
78
79 query := fmt.Sprintf(`update comments set body = "", deleted = strftime('%%Y-%%m-%%dT%%H:%%M:%%SZ', 'now') %s`, whereClause)
80
81 _, err := e.Exec(query, args...)
82 return err
83}
84
85func GetComments(e Execer, filters ...orm.Filter) ([]models.Comment, error) {
86 commentMap := make(map[string]*models.Comment)
87
88 var conditions []string
89 var args []any
90 for _, filter := range filters {
91 conditions = append(conditions, filter.Condition())
92 args = append(args, filter.Arg()...)
93 }
94
95 whereClause := ""
96 if conditions != nil {
97 whereClause = " where " + strings.Join(conditions, " and ")
98 }
99
100 query := fmt.Sprintf(`
101 select
102 id,
103 did,
104 rkey,
105 subject_at,
106 reply_to,
107 body,
108 pull_submission_id,
109 created,
110 edited,
111 deleted
112 from
113 comments
114 %s
115 `, whereClause)
116
117 rows, err := e.Query(query, args...)
118 if err != nil {
119 return nil, err
120 }
121
122 for rows.Next() {
123 var comment models.Comment
124 var created string
125 var rkey, edited, deleted, replyTo sql.Null[string]
126 err := rows.Scan(
127 &comment.Id,
128 &comment.Did,
129 &rkey,
130 &comment.Subject,
131 &replyTo,
132 &comment.Body,
133 &comment.PullSubmissionId,
134 &created,
135 &edited,
136 &deleted,
137 )
138 if err != nil {
139 return nil, err
140 }
141
142 // this is a remnant from old times, newer comments always have rkey
143 if rkey.Valid {
144 comment.Rkey = rkey.V
145 }
146
147 if t, err := time.Parse(time.RFC3339, created); err == nil {
148 comment.Created = t
149 }
150
151 if edited.Valid {
152 if t, err := time.Parse(time.RFC3339, edited.V); err == nil {
153 comment.Edited = &t
154 }
155 }
156
157 if deleted.Valid {
158 if t, err := time.Parse(time.RFC3339, deleted.V); err == nil {
159 comment.Deleted = &t
160 }
161 }
162
163 if replyTo.Valid {
164 rt := syntax.ATURI(replyTo.V)
165 comment.ReplyTo = &rt
166 }
167
168 atUri := comment.AtUri().String()
169 commentMap[atUri] = &comment
170 }
171
172 if err := rows.Err(); err != nil {
173 return nil, err
174 }
175 defer rows.Close()
176
177 // collect references from each comments
178 commentAts := slices.Collect(maps.Keys(commentMap))
179 allReferencs, err := GetReferencesAll(e, orm.FilterIn("from_at", commentAts))
180 if err != nil {
181 return nil, fmt.Errorf("failed to query reference_links: %w", err)
182 }
183 for commentAt, references := range allReferencs {
184 if comment, ok := commentMap[commentAt.String()]; ok {
185 comment.References = references
186 }
187 }
188
189 var comments []models.Comment
190 for _, c := range commentMap {
191 comments = append(comments, *c)
192 }
193
194 sort.Slice(comments, func(i, j int) bool {
195 return comments[i].Created.After(comments[j].Created)
196 })
197
198 return comments, nil
199}