this repo has no description
at sl/shared-stacks 202 lines 4.1 kB view raw
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}