This repository has no description
1package db
2
3import (
4 "database/sql"
5 "errors"
6
7 "github.com/bluesky-social/indigo/atproto/syntax"
8)
9
10type Repo struct {
11 Knot string
12 Owner syntax.DID
13 Rkey syntax.RecordKey
14 RepoDid syntax.DID
15 CreatedAt string
16}
17
18func (d *DB) UpsertRepo(repo Repo) error {
19 var createdAt sql.NullString
20 if repo.CreatedAt != "" {
21 createdAt = sql.NullString{String: repo.CreatedAt, Valid: true}
22 }
23 _, err := d.Exec(
24 `insert or replace into repos (repo_did, knot, owner, rkey, created_at)
25 values (?, ?, ?, ?, ?)`,
26 repo.RepoDid, repo.Knot, repo.Owner, repo.Rkey, createdAt,
27 )
28 return err
29}
30
31func (d *DB) RepoOwners() ([]syntax.DID, error) {
32 repos, err := d.AllRepos()
33 if err != nil {
34 return nil, err
35 }
36 seen := make(map[syntax.DID]struct{}, len(repos))
37 dids := make([]syntax.DID, 0, len(repos))
38 for _, r := range repos {
39 if r.Owner == "" {
40 continue
41 }
42 if _, ok := seen[r.Owner]; ok {
43 continue
44 }
45 seen[r.Owner] = struct{}{}
46 dids = append(dids, r.Owner)
47 }
48 return dids, nil
49}
50
51func (d *DB) Knots() ([]string, error) {
52 rows, err := d.Query(`select distinct knot from repos`)
53 if err != nil {
54 return nil, err
55 }
56 defer rows.Close()
57
58 var knots []string
59 for rows.Next() {
60 var knot string
61 if err := rows.Scan(&knot); err != nil {
62 return nil, err
63 }
64 knots = append(knots, knot)
65 }
66
67 if err := rows.Err(); err != nil {
68 return nil, err
69 }
70
71 return knots, nil
72}
73
74func scanRepo(row interface{ Scan(...any) error }) (*Repo, error) {
75 var knot, owner, rkey, repoDid string
76 if err := row.Scan(&knot, &owner, &rkey, &repoDid); err != nil {
77 return nil, err
78 }
79 return &Repo{
80 Knot: knot,
81 Owner: syntax.DID(owner),
82 Rkey: syntax.RecordKey(rkey),
83 RepoDid: syntax.DID(repoDid),
84 }, nil
85}
86
87func (d *DB) GetRepoByDid(repoDid syntax.DID) (*Repo, error) {
88 return scanRepo(d.QueryRow(
89 `select knot, owner, rkey, repo_did from repos where repo_did = ?`,
90 repoDid.String(),
91 ))
92}
93
94func (d *DB) AllRepos() ([]Repo, error) {
95 rows, err := d.Query(`select knot, owner, rkey, repo_did from repos`)
96 if err != nil {
97 return nil, err
98 }
99 defer rows.Close()
100
101 var repos []Repo
102 for rows.Next() {
103 r, err := scanRepo(rows)
104 if err != nil {
105 return nil, err
106 }
107 repos = append(repos, *r)
108 }
109
110 if err := rows.Err(); err != nil {
111 return nil, err
112 }
113
114 return repos, nil
115}
116
117func (d *DB) DeleteRepo(repoDid syntax.DID) error {
118 _, err := d.Exec(`delete from repos where repo_did = ?`, repoDid)
119 return err
120}
121
122// DeleteRepoByOwnerRkey deletes a repo by (owner,rkey) pair and returns deleted repos DID.
123func (d *DB) DeleteRepoByOwnerRkey(owner syntax.DID, rkey syntax.RecordKey) (syntax.DID, error) {
124 var repoDid string
125 err := d.QueryRow(
126 `delete from repos where owner = ? and rkey = ? returning repo_did`,
127 owner.String(), rkey.String(),
128 ).Scan(&repoDid)
129 if errors.Is(err, sql.ErrNoRows) {
130 return "", nil
131 }
132 if err != nil {
133 return "", err
134 }
135 return syntax.DID(repoDid), nil
136}