forked from
tangled.org/core
fork
Configure Feed
Select the types of activity you want to include in your feed.
Monorepo for Tangled
fork
Configure Feed
Select the types of activity you want to include in your feed.
1package db
2
3import (
4 "log"
5 "time"
6)
7
8type Follow struct {
9 UserDid string
10 SubjectDid string
11 FollowedAt time.Time
12 Rkey string
13}
14
15func AddFollow(e Execer, userDid, subjectDid, rkey string) error {
16 query := `insert or ignore into follows (user_did, subject_did, rkey) values (?, ?, ?)`
17 _, err := e.Exec(query, userDid, subjectDid, rkey)
18 return err
19}
20
21// Get a follow record
22func GetFollow(e Execer, userDid, subjectDid string) (*Follow, error) {
23 query := `select user_did, subject_did, followed_at, rkey from follows where user_did = ? and subject_did = ?`
24 row := e.QueryRow(query, userDid, subjectDid)
25
26 var follow Follow
27 var followedAt string
28 err := row.Scan(&follow.UserDid, &follow.SubjectDid, &followedAt, &follow.Rkey)
29 if err != nil {
30 return nil, err
31 }
32
33 followedAtTime, err := time.Parse(time.RFC3339, followedAt)
34 if err != nil {
35 log.Println("unable to determine followed at time")
36 follow.FollowedAt = time.Now()
37 } else {
38 follow.FollowedAt = followedAtTime
39 }
40
41 return &follow, nil
42}
43
44// Remove a follow
45func DeleteFollow(e Execer, userDid, subjectDid string) error {
46 _, err := e.Exec(`delete from follows where user_did = ? and subject_did = ?`, userDid, subjectDid)
47 return err
48}
49
50// Remove a follow
51func DeleteFollowByRkey(e Execer, userDid, rkey string) error {
52 _, err := e.Exec(`delete from follows where user_did = ? and rkey = ?`, userDid, rkey)
53 return err
54}
55
56func GetFollowerFollowing(e Execer, did string) (int, int, error) {
57 followers, following := 0, 0
58 err := e.QueryRow(
59 `SELECT
60 COUNT(CASE WHEN subject_did = ? THEN 1 END) AS followers,
61 COUNT(CASE WHEN user_did = ? THEN 1 END) AS following
62 FROM follows;`, did, did).Scan(&followers, &following)
63 if err != nil {
64 return 0, 0, err
65 }
66 return followers, following, nil
67}
68
69type FollowStatus int
70
71const (
72 IsNotFollowing FollowStatus = iota
73 IsFollowing
74 IsSelf
75)
76
77func (s FollowStatus) String() string {
78 switch s {
79 case IsNotFollowing:
80 return "IsNotFollowing"
81 case IsFollowing:
82 return "IsFollowing"
83 case IsSelf:
84 return "IsSelf"
85 default:
86 return "IsNotFollowing"
87 }
88}
89
90func GetFollowStatus(e Execer, userDid, subjectDid string) FollowStatus {
91 if userDid == subjectDid {
92 return IsSelf
93 } else if _, err := GetFollow(e, userDid, subjectDid); err != nil {
94 return IsNotFollowing
95 } else {
96 return IsFollowing
97 }
98}
99
100func GetAllFollows(e Execer, limit int) ([]Follow, error) {
101 var follows []Follow
102
103 rows, err := e.Query(`
104 select user_did, subject_did, followed_at, rkey
105 from follows
106 order by followed_at desc
107 limit ?`, limit,
108 )
109 if err != nil {
110 return nil, err
111 }
112 defer rows.Close()
113
114 for rows.Next() {
115 var follow Follow
116 var followedAt string
117 if err := rows.Scan(&follow.UserDid, &follow.SubjectDid, &followedAt, &follow.Rkey); err != nil {
118 return nil, err
119 }
120
121 followedAtTime, err := time.Parse(time.RFC3339, followedAt)
122 if err != nil {
123 log.Println("unable to determine followed at time")
124 follow.FollowedAt = time.Now()
125 } else {
126 follow.FollowedAt = followedAtTime
127 }
128
129 follows = append(follows, follow)
130 }
131
132 if err := rows.Err(); err != nil {
133 return nil, err
134 }
135
136 return follows, nil
137}