A vibe coded tangled fork which supports pijul.
at 0e761eb1e072581ccc571b395a22f8e88ef929f2 140 lines 3.8 kB view raw
1package db 2 3import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/bluesky-social/indigo/atproto/syntax" 9 "tangled.org/core/appview/models" 10) 11 12func AddReaction(e Execer, did string, subjectAt syntax.ATURI, kind models.ReactionKind, rkey string) error { 13 query := `insert or ignore into reactions (did, subject_at, kind, rkey) values (?, ?, ?, ?)` 14 _, err := e.Exec(query, did, subjectAt, kind, rkey) 15 return err 16} 17 18// Get a reaction record 19func GetReaction(e Execer, did string, subjectAt syntax.ATURI, kind models.ReactionKind) (*models.Reaction, error) { 20 query := ` 21 select did, subject_at, created, rkey 22 from reactions 23 where did = ? and subject_at = ? and kind = ?` 24 row := e.QueryRow(query, did, subjectAt, kind) 25 26 var reaction models.Reaction 27 var created string 28 err := row.Scan(&reaction.ReactedByDid, &reaction.ThreadAt, &created, &reaction.Rkey) 29 if err != nil { 30 return nil, err 31 } 32 33 createdAtTime, err := time.Parse(time.RFC3339, created) 34 if err != nil { 35 log.Println("unable to determine followed at time") 36 reaction.Created = time.Now() 37 } else { 38 reaction.Created = createdAtTime 39 } 40 41 return &reaction, nil 42} 43 44// Remove a reaction 45func DeleteReaction(e Execer, did syntax.DID, subjectAt syntax.ATURI, kind models.ReactionKind) ([]syntax.ATURI, error) { 46 var deleted []syntax.ATURI 47 rows, err := e.Query( 48 `delete from reactions 49 where did = ? and subject_at = ? and kind = ? 50 returning at_uri`, 51 did, 52 subjectAt, 53 kind, 54 ) 55 if err != nil { 56 return nil, fmt.Errorf("deleting stars: %w", err) 57 } 58 defer rows.Close() 59 60 for rows.Next() { 61 var aturi syntax.ATURI 62 if err := rows.Scan(&aturi); err != nil { 63 return nil, fmt.Errorf("scanning at_uri: %w", err) 64 } 65 deleted = append(deleted, aturi) 66 } 67 return deleted, nil 68} 69 70// Remove a reaction 71func DeleteReactionByRkey(e Execer, did string, rkey string) error { 72 _, err := e.Exec(`delete from reactions where did = ? and rkey = ?`, did, rkey) 73 return err 74} 75 76func GetReactionCount(e Execer, subjectAt syntax.ATURI, kind models.ReactionKind) (int, error) { 77 count := 0 78 err := e.QueryRow( 79 `select count(did) from reactions where subject_at = ? and kind = ?`, subjectAt, kind).Scan(&count) 80 if err != nil { 81 return 0, err 82 } 83 return count, nil 84} 85 86func GetReactionMap(e Execer, userLimit int, subjectAt syntax.ATURI) (map[models.ReactionKind]models.ReactionDisplayData, error) { 87 query := ` 88 select kind, did, 89 row_number() over (partition by kind order by created asc) as rn, 90 count(*) over (partition by kind) as total 91 from reactions 92 where subject_at = ? 93 order by kind, created asc` 94 95 rows, err := e.Query(query, subjectAt) 96 if err != nil { 97 return nil, err 98 } 99 defer rows.Close() 100 101 reactionMap := map[models.ReactionKind]models.ReactionDisplayData{} 102 for _, kind := range models.OrderedReactionKinds { 103 reactionMap[kind] = models.ReactionDisplayData{Count: 0, Users: []string{}} 104 } 105 106 for rows.Next() { 107 var kind models.ReactionKind 108 var did string 109 var rn, total int 110 if err := rows.Scan(&kind, &did, &rn, &total); err != nil { 111 return nil, err 112 } 113 114 data := reactionMap[kind] 115 data.Count = total 116 if userLimit > 0 && rn <= userLimit { 117 data.Users = append(data.Users, did) 118 } 119 reactionMap[kind] = data 120 } 121 122 return reactionMap, rows.Err() 123} 124 125func GetReactionStatus(e Execer, userDid string, threadAt syntax.ATURI, kind models.ReactionKind) bool { 126 if _, err := GetReaction(e, userDid, threadAt, kind); err != nil { 127 return false 128 } else { 129 return true 130 } 131} 132 133func GetReactionStatusMap(e Execer, userDid string, threadAt syntax.ATURI) map[models.ReactionKind]bool { 134 statusMap := map[models.ReactionKind]bool{} 135 for _, kind := range models.OrderedReactionKinds { 136 count := GetReactionStatus(e, userDid, threadAt, kind) 137 statusMap[kind] = count 138 } 139 return statusMap 140}