A vibe coded tangled fork which supports pijul.
at 1237bf9f58e4ba5d13d5437f2f82a2078572e229 275 lines 5.8 kB view raw
1package db 2 3import ( 4 "context" 5 "database/sql" 6 "errors" 7 "fmt" 8 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 "tangled.org/core/appview/pagination" 11 "tangled.org/core/knotmirror/models" 12) 13 14func AddRepo(ctx context.Context, e *sql.DB, did syntax.DID, rkey syntax.RecordKey, cid syntax.CID, name, knot string) error { 15 if _, err := e.ExecContext(ctx, 16 `insert into repos (did, rkey, cid, name, knot_domain) 17 values ($1, $2, $3, $4, $5)`, 18 did, rkey, cid, name, knot, 19 ); err != nil { 20 return fmt.Errorf("inserting repo: %w", err) 21 } 22 return nil 23} 24 25func UpsertRepo(ctx context.Context, e *sql.DB, repo *models.Repo) error { 26 if _, err := e.ExecContext(ctx, 27 `insert into repos (did, rkey, cid, name, knot_domain, git_rev, repo_sha, state, error_msg, retry_count, retry_after) 28 values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) 29 on conflict(did, rkey) do update set 30 cid = excluded.cid, 31 name = excluded.name, 32 knot_domain = excluded.knot_domain, 33 git_rev = excluded.git_rev, 34 repo_sha = excluded.repo_sha, 35 state = excluded.state, 36 error_msg = excluded.error_msg, 37 retry_count = excluded.retry_count, 38 retry_after = excluded.retry_after`, 39 // where repos.cid != excluded.cid`, 40 repo.Did, 41 repo.Rkey, 42 repo.Cid, 43 repo.Name, 44 repo.KnotDomain, 45 repo.GitRev, 46 repo.RepoSha, 47 repo.State, 48 repo.ErrorMsg, 49 repo.RetryCount, 50 repo.RetryAfter, 51 ); err != nil { 52 return fmt.Errorf("upserting repo: %w", err) 53 } 54 return nil 55} 56 57func UpdateRepoState(ctx context.Context, e *sql.DB, did syntax.DID, rkey syntax.RecordKey, state models.RepoState) error { 58 if _, err := e.ExecContext(ctx, 59 `update repos 60 set state = $1 61 where did = $2 and rkey = $3`, 62 state, 63 did, rkey, 64 ); err != nil { 65 return fmt.Errorf("updating repo: %w", err) 66 } 67 return nil 68} 69 70func DeleteRepo(ctx context.Context, e *sql.DB, did syntax.DID, rkey syntax.RecordKey) error { 71 if _, err := e.ExecContext(ctx, 72 `delete from repos where did = $1 and rkey = $2`, 73 did, 74 rkey, 75 ); err != nil { 76 return fmt.Errorf("deleting repo: %w", err) 77 } 78 return nil 79} 80 81func GetRepoByName(ctx context.Context, e *sql.DB, did syntax.DID, name string) (*models.Repo, error) { 82 var repo models.Repo 83 if err := e.QueryRowContext(ctx, 84 `select 85 did, 86 rkey, 87 cid, 88 name, 89 knot_domain, 90 git_rev, 91 repo_sha, 92 state, 93 error_msg, 94 retry_count, 95 retry_after 96 from repos 97 where did = $1 and name = $2`, 98 did, 99 name, 100 ).Scan( 101 &repo.Did, 102 &repo.Rkey, 103 &repo.Cid, 104 &repo.Name, 105 &repo.KnotDomain, 106 &repo.GitRev, 107 &repo.RepoSha, 108 &repo.State, 109 &repo.ErrorMsg, 110 &repo.RetryCount, 111 &repo.RetryAfter, 112 ); err != nil { 113 if errors.Is(err, sql.ErrNoRows) { 114 return nil, nil 115 } 116 return nil, fmt.Errorf("querying repo: %w", err) 117 } 118 return &repo, nil 119} 120 121func GetRepoByAtUri(ctx context.Context, e *sql.DB, aturi syntax.ATURI) (*models.Repo, error) { 122 var repo models.Repo 123 if err := e.QueryRowContext(ctx, 124 `select 125 did, 126 rkey, 127 cid, 128 name, 129 knot_domain, 130 git_rev, 131 repo_sha, 132 state, 133 error_msg, 134 retry_count, 135 retry_after 136 from repos 137 where at_uri = $1`, 138 aturi, 139 ).Scan( 140 &repo.Did, 141 &repo.Rkey, 142 &repo.Cid, 143 &repo.Name, 144 &repo.KnotDomain, 145 &repo.GitRev, 146 &repo.RepoSha, 147 &repo.State, 148 &repo.ErrorMsg, 149 &repo.RetryCount, 150 &repo.RetryAfter, 151 ); err != nil { 152 if errors.Is(err, sql.ErrNoRows) { 153 return nil, nil 154 } 155 return nil, fmt.Errorf("querying repo: %w", err) 156 } 157 return &repo, nil 158} 159 160func ListRepos(ctx context.Context, e *sql.DB, page pagination.Page, did, knot, state string) ([]models.Repo, error) { 161 var conditions []string 162 var args []any 163 164 pageClause := "" 165 if page.Limit > 0 { 166 pageClause = " limit $1 offset $2 " 167 args = append(args, page.Limit, page.Offset) 168 } 169 170 whereClause := "" 171 if did != "" { 172 conditions = append(conditions, fmt.Sprintf("did = $%d", len(args)+1)) 173 args = append(args, did) 174 } 175 if knot != "" { 176 conditions = append(conditions, fmt.Sprintf("knot_domain = $%d", len(args)+1)) 177 args = append(args, knot) 178 } 179 if state != "" { 180 conditions = append(conditions, fmt.Sprintf("state = $%d", len(args)+1)) 181 args = append(args, state) 182 } 183 if len(conditions) > 0 { 184 whereClause = "WHERE " + conditions[0] 185 for _, condition := range conditions[1:] { 186 whereClause += " AND " + condition 187 } 188 } 189 190 query := ` 191 select 192 did, 193 rkey, 194 cid, 195 name, 196 knot_domain, 197 git_rev, 198 repo_sha, 199 state, 200 error_msg, 201 retry_count, 202 retry_after 203 from repos 204 ` + whereClause + pageClause 205 rows, err := e.QueryContext(ctx, query, args...) 206 if err != nil { 207 return nil, err 208 } 209 defer rows.Close() 210 211 var repos []models.Repo 212 for rows.Next() { 213 var repo models.Repo 214 if err := rows.Scan( 215 &repo.Did, 216 &repo.Rkey, 217 &repo.Cid, 218 &repo.Name, 219 &repo.KnotDomain, 220 &repo.GitRev, 221 &repo.RepoSha, 222 &repo.State, 223 &repo.ErrorMsg, 224 &repo.RetryCount, 225 &repo.RetryAfter, 226 ); err != nil { 227 return nil, fmt.Errorf("scanning row: %w", err) 228 } 229 repos = append(repos, repo) 230 } 231 if err := rows.Err(); err != nil { 232 return nil, fmt.Errorf("scanning rows: %w ", err) 233 } 234 235 return repos, nil 236} 237 238func GetRepoCountsByState(ctx context.Context, e *sql.DB) (map[models.RepoState]int64, error) { 239 const q = ` 240 SELECT state, COUNT(*) 241 FROM repos 242 GROUP BY state 243 ` 244 245 rows, err := e.QueryContext(ctx, q) 246 if err != nil { 247 return nil, err 248 } 249 defer rows.Close() 250 251 counts := make(map[models.RepoState]int64) 252 253 for rows.Next() { 254 var state string 255 var count int64 256 257 if err := rows.Scan(&state, &count); err != nil { 258 return nil, err 259 } 260 261 counts[models.RepoState(state)] = count 262 } 263 264 if err := rows.Err(); err != nil { 265 return nil, err 266 } 267 268 for _, s := range models.AllRepoStates { 269 if _, ok := counts[s]; !ok { 270 counts[s] = 0 271 } 272 } 273 274 return counts, nil 275}