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