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