forked from
tangled.org/core
fork
Configure Feed
Select the types of activity you want to include in your feed.
this repo has no description
fork
Configure Feed
Select the types of activity you want to include in your feed.
1package db
2
3import (
4 "database/sql"
5 "fmt"
6 "time"
7
8 "github.com/bluesky-social/indigo/atproto/syntax"
9 "tangled.sh/tangled.sh/core/api/tangled"
10)
11
12type Repo struct {
13 Did string
14 Name string
15 Knot string
16 Rkey string
17 Created time.Time
18 AtUri string
19 Description string
20
21 // optionally, populate this when querying for reverse mappings
22 RepoStats *RepoStats
23
24 // optional
25 Source string
26}
27
28func (r Repo) RepoAt() syntax.ATURI {
29 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", r.Did, tangled.RepoNSID, r.Rkey))
30}
31
32func GetAllRepos(e Execer, limit int) ([]Repo, error) {
33 var repos []Repo
34
35 rows, err := e.Query(
36 `select did, name, knot, rkey, description, created, source
37 from repos
38 order by created desc
39 limit ?
40 `,
41 limit,
42 )
43 if err != nil {
44 return nil, err
45 }
46 defer rows.Close()
47
48 for rows.Next() {
49 var repo Repo
50 err := scanRepo(
51 rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Description, &repo.Created, &repo.Source,
52 )
53 if err != nil {
54 return nil, err
55 }
56 repos = append(repos, repo)
57 }
58
59 if err := rows.Err(); err != nil {
60 return nil, err
61 }
62
63 return repos, nil
64}
65
66func GetAllReposByDid(e Execer, did string) ([]Repo, error) {
67 var repos []Repo
68
69 rows, err := e.Query(
70 `select
71 r.did,
72 r.name,
73 r.knot,
74 r.rkey,
75 r.description,
76 r.created,
77 count(s.id) as star_count,
78 r.source
79 from
80 repos r
81 left join
82 stars s on r.at_uri = s.repo_at
83 where
84 r.did = ?
85 group by
86 r.at_uri
87 order by r.created desc`,
88 did)
89 if err != nil {
90 return nil, err
91 }
92 defer rows.Close()
93
94 for rows.Next() {
95 var repo Repo
96 var repoStats RepoStats
97 var createdAt string
98 var nullableDescription sql.NullString
99 var nullableSource sql.NullString
100
101 err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repoStats.StarCount, &nullableSource)
102 if err != nil {
103 return nil, err
104 }
105
106 if nullableDescription.Valid {
107 repo.Description = nullableDescription.String
108 }
109
110 if nullableSource.Valid {
111 repo.Source = nullableSource.String
112 }
113
114 createdAtTime, err := time.Parse(time.RFC3339, createdAt)
115 if err != nil {
116 repo.Created = time.Now()
117 } else {
118 repo.Created = createdAtTime
119 }
120
121 repo.RepoStats = &repoStats
122
123 repos = append(repos, repo)
124 }
125
126 if err := rows.Err(); err != nil {
127 return nil, err
128 }
129
130 return repos, nil
131}
132
133func GetRepo(e Execer, did, name string) (*Repo, error) {
134 var repo Repo
135 var nullableDescription sql.NullString
136
137 row := e.QueryRow(`select did, name, knot, created, at_uri, description from repos where did = ? and name = ?`, did, name)
138
139 var createdAt string
140 if err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt, &repo.AtUri, &nullableDescription); err != nil {
141 return nil, err
142 }
143 createdAtTime, _ := time.Parse(time.RFC3339, createdAt)
144 repo.Created = createdAtTime
145
146 if nullableDescription.Valid {
147 repo.Description = nullableDescription.String
148 } else {
149 repo.Description = ""
150 }
151
152 return &repo, nil
153}
154
155func GetRepoByAtUri(e Execer, atUri string) (*Repo, error) {
156 var repo Repo
157 var nullableDescription sql.NullString
158
159 row := e.QueryRow(`select did, name, knot, created, at_uri, description from repos where at_uri = ?`, atUri)
160
161 var createdAt string
162 if err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt, &repo.AtUri, &nullableDescription); err != nil {
163 return nil, err
164 }
165 createdAtTime, _ := time.Parse(time.RFC3339, createdAt)
166 repo.Created = createdAtTime
167
168 if nullableDescription.Valid {
169 repo.Description = nullableDescription.String
170 } else {
171 repo.Description = ""
172 }
173
174 return &repo, nil
175}
176
177func AddRepo(e Execer, repo *Repo) error {
178 _, err := e.Exec(
179 `insert into repos
180 (did, name, knot, rkey, at_uri, description, source)
181 values (?, ?, ?, ?, ?, ?, ?)`,
182 repo.Did, repo.Name, repo.Knot, repo.Rkey, repo.AtUri, repo.Description, repo.Source,
183 )
184 return err
185}
186
187func RemoveRepo(e Execer, did, name string) error {
188 _, err := e.Exec(`delete from repos where did = ? and name = ?`, did, name)
189 return err
190}
191
192func GetRepoSource(e Execer, repoAt syntax.ATURI) (string, error) {
193 var nullableSource sql.NullString
194 err := e.QueryRow(`select source from repos where at_uri = ?`, repoAt).Scan(&nullableSource)
195 if err != nil {
196 return "", err
197 }
198 return nullableSource.String, nil
199}
200
201func GetForksByDid(e Execer, did string) ([]Repo, error) {
202 var repos []Repo
203
204 rows, err := e.Query(
205 `select did, name, knot, rkey, description, created, at_uri, source
206 from repos
207 where did = ? and source is not null and source != ''
208 order by created desc`,
209 did,
210 )
211 if err != nil {
212 return nil, err
213 }
214 defer rows.Close()
215
216 for rows.Next() {
217 var repo Repo
218 var createdAt string
219 var nullableDescription sql.NullString
220 var nullableSource sql.NullString
221
222 err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repo.AtUri, &nullableSource)
223 if err != nil {
224 return nil, err
225 }
226
227 if nullableDescription.Valid {
228 repo.Description = nullableDescription.String
229 }
230
231 if nullableSource.Valid {
232 repo.Source = nullableSource.String
233 }
234
235 createdAtTime, err := time.Parse(time.RFC3339, createdAt)
236 if err != nil {
237 repo.Created = time.Now()
238 } else {
239 repo.Created = createdAtTime
240 }
241
242 repos = append(repos, repo)
243 }
244
245 if err := rows.Err(); err != nil {
246 return nil, err
247 }
248
249 return repos, nil
250}
251
252func GetForkByDid(e Execer, did string, name string) (*Repo, error) {
253 var repo Repo
254 var createdAt string
255 var nullableDescription sql.NullString
256 var nullableSource sql.NullString
257
258 row := e.QueryRow(
259 `select did, name, knot, rkey, description, created, at_uri, source
260 from repos
261 where did = ? and name = ? and source is not null and source != ''`,
262 did, name,
263 )
264
265 err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repo.AtUri, &nullableSource)
266 if err != nil {
267 return nil, err
268 }
269
270 if nullableDescription.Valid {
271 repo.Description = nullableDescription.String
272 }
273
274 if nullableSource.Valid {
275 repo.Source = nullableSource.String
276 }
277
278 createdAtTime, err := time.Parse(time.RFC3339, createdAt)
279 if err != nil {
280 repo.Created = time.Now()
281 } else {
282 repo.Created = createdAtTime
283 }
284
285 return &repo, nil
286}
287
288func AddCollaborator(e Execer, collaborator, repoOwnerDid, repoName, repoKnot string) error {
289 _, err := e.Exec(
290 `insert into collaborators (did, repo)
291 values (?, (select id from repos where did = ? and name = ? and knot = ?));`,
292 collaborator, repoOwnerDid, repoName, repoKnot)
293 return err
294}
295
296func UpdateDescription(e Execer, repoAt, newDescription string) error {
297 _, err := e.Exec(
298 `update repos set description = ? where at_uri = ?`, newDescription, repoAt)
299 return err
300}
301
302func CollaboratingIn(e Execer, collaborator string) ([]Repo, error) {
303 var repos []Repo
304
305 rows, err := e.Query(
306 `select
307 r.did, r.name, r.knot, r.rkey, r.description, r.created, count(s.id) as star_count
308 from
309 repos r
310 join
311 collaborators c on r.id = c.repo
312 left join
313 stars s on r.at_uri = s.repo_at
314 where
315 c.did = ?
316 group by
317 r.id;`, collaborator)
318 if err != nil {
319 return nil, err
320 }
321 defer rows.Close()
322
323 for rows.Next() {
324 var repo Repo
325 var repoStats RepoStats
326 var createdAt string
327 var nullableDescription sql.NullString
328
329 err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repoStats.StarCount)
330 if err != nil {
331 return nil, err
332 }
333
334 if nullableDescription.Valid {
335 repo.Description = nullableDescription.String
336 } else {
337 repo.Description = ""
338 }
339
340 createdAtTime, err := time.Parse(time.RFC3339, createdAt)
341 if err != nil {
342 repo.Created = time.Now()
343 } else {
344 repo.Created = createdAtTime
345 }
346
347 repo.RepoStats = &repoStats
348
349 repos = append(repos, repo)
350 }
351
352 if err := rows.Err(); err != nil {
353 return nil, err
354 }
355
356 return repos, nil
357}
358
359type RepoStats struct {
360 StarCount int
361 IssueCount IssueCount
362 PullCount PullCount
363}
364
365func scanRepo(rows *sql.Rows, did, name, knot, rkey, description *string, created *time.Time, source *string) error {
366 var createdAt string
367 var nullableDescription sql.NullString
368 var nullableSource sql.NullString
369 if err := rows.Scan(did, name, knot, rkey, &nullableDescription, &createdAt, &nullableSource); err != nil {
370 return err
371 }
372
373 if nullableDescription.Valid {
374 *description = nullableDescription.String
375 } else {
376 *description = ""
377 }
378
379 createdAtTime, err := time.Parse(time.RFC3339, createdAt)
380 if err != nil {
381 *created = time.Now()
382 } else {
383 *created = createdAtTime
384 }
385
386 if nullableSource.Valid {
387 *source = nullableSource.String
388 } else {
389 *source = ""
390 }
391
392 return nil
393}