this repo has no description
1package db
2
3import (
4 "fmt"
5 "log"
6 "strings"
7 "time"
8)
9
10type Follow struct {
11 UserDid string
12 SubjectDid string
13 FollowedAt time.Time
14 Rkey string
15}
16
17func AddFollow(e Execer, follow *Follow) error {
18 query := `insert or ignore into follows (user_did, subject_did, rkey) values (?, ?, ?)`
19 _, err := e.Exec(query, follow.UserDid, follow.SubjectDid, follow.Rkey)
20 return err
21}
22
23// Get a follow record
24func GetFollow(e Execer, userDid, subjectDid string) (*Follow, error) {
25 query := `select user_did, subject_did, followed_at, rkey from follows where user_did = ? and subject_did = ?`
26 row := e.QueryRow(query, userDid, subjectDid)
27
28 var follow Follow
29 var followedAt string
30 err := row.Scan(&follow.UserDid, &follow.SubjectDid, &followedAt, &follow.Rkey)
31 if err != nil {
32 return nil, err
33 }
34
35 followedAtTime, err := time.Parse(time.RFC3339, followedAt)
36 if err != nil {
37 log.Println("unable to determine followed at time")
38 follow.FollowedAt = time.Now()
39 } else {
40 follow.FollowedAt = followedAtTime
41 }
42
43 return &follow, nil
44}
45
46// Remove a follow
47func DeleteFollow(e Execer, userDid, subjectDid string) error {
48 _, err := e.Exec(`delete from follows where user_did = ? and subject_did = ?`, userDid, subjectDid)
49 return err
50}
51
52// Remove a follow
53func DeleteFollowByRkey(e Execer, userDid, rkey string) error {
54 _, err := e.Exec(`delete from follows where user_did = ? and rkey = ?`, userDid, rkey)
55 return err
56}
57
58func GetFollowerFollowingCount(e Execer, did string) (int, int, error) {
59 followers, following := 0, 0
60 err := e.QueryRow(
61 `SELECT
62 COUNT(CASE WHEN subject_did = ? THEN 1 END) AS followers,
63 COUNT(CASE WHEN user_did = ? THEN 1 END) AS following
64 FROM follows;`, did, did).Scan(&followers, &following)
65 if err != nil {
66 return 0, 0, err
67 }
68 return followers, following, nil
69}
70
71func GetFollows(e Execer, limit int, filters ...filter) ([]Follow, error) {
72 var follows []Follow
73
74 var conditions []string
75 var args []any
76 for _, filter := range filters {
77 conditions = append(conditions, filter.Condition())
78 args = append(args, filter.Arg()...)
79 }
80
81 whereClause := ""
82 if conditions != nil {
83 whereClause = " where " + strings.Join(conditions, " and ")
84 }
85 limitClause := ""
86 if limit > 0 {
87 limitClause = " limit ?"
88 args = append(args, limit)
89 }
90
91 query := fmt.Sprintf(
92 `select user_did, subject_did, followed_at, rkey
93 from follows
94 %s
95 order by followed_at desc
96 %s
97 `, whereClause, limitClause)
98
99 rows, err := e.Query(query, args...)
100 if err != nil {
101 return nil, err
102 }
103 for rows.Next() {
104 var follow Follow
105 var followedAt string
106 err := rows.Scan(
107 &follow.UserDid,
108 &follow.SubjectDid,
109 &followedAt,
110 &follow.Rkey,
111 )
112 if err != nil {
113 return nil, err
114 }
115 followedAtTime, err := time.Parse(time.RFC3339, followedAt)
116 if err != nil {
117 log.Println("unable to determine followed at time")
118 follow.FollowedAt = time.Now()
119 } else {
120 follow.FollowedAt = followedAtTime
121 }
122 follows = append(follows, follow)
123 }
124 return follows, nil
125}
126
127func GetFollowers(e Execer, did string) ([]Follow, error) {
128 return GetFollows(e, 0, FilterEq("subject_did", did))
129}
130
131func GetFollowing(e Execer, did string) ([]Follow, error) {
132 return GetFollows(e, 0, FilterEq("user_did", did))
133}
134
135type FollowStatus int
136
137const (
138 IsNotFollowing FollowStatus = iota
139 IsFollowing
140 IsSelf
141)
142
143func (s FollowStatus) String() string {
144 switch s {
145 case IsNotFollowing:
146 return "IsNotFollowing"
147 case IsFollowing:
148 return "IsFollowing"
149 case IsSelf:
150 return "IsSelf"
151 default:
152 return "IsNotFollowing"
153 }
154}
155
156func GetFollowStatus(e Execer, userDid, subjectDid string) FollowStatus {
157 if userDid == subjectDid {
158 return IsSelf
159 } else if _, err := GetFollow(e, userDid, subjectDid); err != nil {
160 return IsNotFollowing
161 } else {
162 return IsFollowing
163 }
164}