forked from tangled.org/core
this repo has no description
1package db 2 3import ( 4 "database/sql" 5 "time" 6 7 "github.com/bluesky-social/indigo/atproto/syntax" 8) 9 10type Issue struct { 11 RepoAt syntax.ATURI 12 OwnerDid string 13 IssueId int 14 IssueAt string 15 Created *time.Time 16 Title string 17 Body string 18 Open bool 19} 20 21type Comment struct { 22 OwnerDid string 23 RepoAt syntax.ATURI 24 CommentAt string 25 Issue int 26 CommentId int 27 Body string 28 Created *time.Time 29} 30 31func NewIssue(tx *sql.Tx, issue *Issue) error { 32 defer tx.Rollback() 33 34 _, err := tx.Exec(` 35 insert or ignore into repo_issue_seqs (repo_at, next_issue_id) 36 values (?, 1) 37 `, issue.RepoAt) 38 if err != nil { 39 return err 40 } 41 42 var nextId int 43 err = tx.QueryRow(` 44 update repo_issue_seqs 45 set next_issue_id = next_issue_id + 1 46 where repo_at = ? 47 returning next_issue_id - 1 48 `, issue.RepoAt).Scan(&nextId) 49 if err != nil { 50 return err 51 } 52 53 issue.IssueId = nextId 54 55 _, err = tx.Exec(` 56 insert into issues (repo_at, owner_did, issue_id, title, body) 57 values (?, ?, ?, ?, ?) 58 `, issue.RepoAt, issue.OwnerDid, issue.IssueId, issue.Title, issue.Body) 59 if err != nil { 60 return err 61 } 62 63 if err := tx.Commit(); err != nil { 64 return err 65 } 66 67 return nil 68} 69 70func SetIssueAt(e Execer, repoAt syntax.ATURI, issueId int, issueAt string) error { 71 _, err := e.Exec(`update issues set issue_at = ? where repo_at = ? and issue_id = ?`, issueAt, repoAt, issueId) 72 return err 73} 74 75func GetIssueAt(e Execer, repoAt syntax.ATURI, issueId int) (string, error) { 76 var issueAt string 77 err := e.QueryRow(`select issue_at from issues where repo_at = ? and issue_id = ?`, repoAt, issueId).Scan(&issueAt) 78 return issueAt, err 79} 80 81func GetIssueId(e Execer, repoAt syntax.ATURI) (int, error) { 82 var issueId int 83 err := e.QueryRow(`select next_issue_id from repo_issue_seqs where repo_at = ?`, repoAt).Scan(&issueId) 84 return issueId - 1, err 85} 86 87func GetIssueOwnerDid(e Execer, repoAt syntax.ATURI, issueId int) (string, error) { 88 var ownerDid string 89 err := e.QueryRow(`select owner_did from issues where repo_at = ? and issue_id = ?`, repoAt, issueId).Scan(&ownerDid) 90 return ownerDid, err 91} 92 93func GetIssues(e Execer, repoAt syntax.ATURI) ([]Issue, error) { 94 var issues []Issue 95 96 rows, err := e.Query(`select owner_did, issue_id, created, title, body, open from issues where repo_at = ? order by created desc`, repoAt) 97 if err != nil { 98 return nil, err 99 } 100 defer rows.Close() 101 102 for rows.Next() { 103 var issue Issue 104 var createdAt string 105 err := rows.Scan(&issue.OwnerDid, &issue.IssueId, &createdAt, &issue.Title, &issue.Body, &issue.Open) 106 if err != nil { 107 return nil, err 108 } 109 110 createdTime, err := time.Parse(time.RFC3339, createdAt) 111 if err != nil { 112 return nil, err 113 } 114 issue.Created = &createdTime 115 116 issues = append(issues, issue) 117 } 118 119 if err := rows.Err(); err != nil { 120 return nil, err 121 } 122 123 return issues, nil 124} 125 126func GetIssue(e Execer, repoAt syntax.ATURI, issueId int) (*Issue, error) { 127 query := `select owner_did, created, title, body, open from issues where repo_at = ? and issue_id = ?` 128 row := e.QueryRow(query, repoAt, issueId) 129 130 var issue Issue 131 var createdAt string 132 err := row.Scan(&issue.OwnerDid, &createdAt, &issue.Title, &issue.Body, &issue.Open) 133 if err != nil { 134 return nil, err 135 } 136 137 createdTime, err := time.Parse(time.RFC3339, createdAt) 138 if err != nil { 139 return nil, err 140 } 141 issue.Created = &createdTime 142 143 return &issue, nil 144} 145 146func GetIssueWithComments(e Execer, repoAt syntax.ATURI, issueId int) (*Issue, []Comment, error) { 147 query := `select owner_did, issue_id, created, title, body, open from issues where repo_at = ? and issue_id = ?` 148 row := e.QueryRow(query, repoAt, issueId) 149 150 var issue Issue 151 var createdAt string 152 err := row.Scan(&issue.OwnerDid, &issue.IssueId, &createdAt, &issue.Title, &issue.Body, &issue.Open) 153 if err != nil { 154 return nil, nil, err 155 } 156 157 createdTime, err := time.Parse(time.RFC3339, createdAt) 158 if err != nil { 159 return nil, nil, err 160 } 161 issue.Created = &createdTime 162 163 comments, err := GetComments(e, repoAt, issueId) 164 if err != nil { 165 return nil, nil, err 166 } 167 168 return &issue, comments, nil 169} 170 171func NewComment(e Execer, comment *Comment) error { 172 query := `insert into comments (owner_did, repo_at, comment_at, issue_id, comment_id, body) values (?, ?, ?, ?, ?, ?)` 173 _, err := e.Exec( 174 query, 175 comment.OwnerDid, 176 comment.RepoAt, 177 comment.CommentAt, 178 comment.Issue, 179 comment.CommentId, 180 comment.Body, 181 ) 182 return err 183} 184 185func GetComments(e Execer, repoAt syntax.ATURI, issueId int) ([]Comment, error) { 186 var comments []Comment 187 188 rows, err := e.Query(`select owner_did, issue_id, comment_id, comment_at, body, created from comments where repo_at = ? and issue_id = ? order by created asc`, repoAt, issueId) 189 if err == sql.ErrNoRows { 190 return []Comment{}, nil 191 } 192 if err != nil { 193 return nil, err 194 } 195 defer rows.Close() 196 197 for rows.Next() { 198 var comment Comment 199 var createdAt string 200 err := rows.Scan(&comment.OwnerDid, &comment.Issue, &comment.CommentId, &comment.CommentAt, &comment.Body, &createdAt) 201 if err != nil { 202 return nil, err 203 } 204 205 createdAtTime, err := time.Parse(time.RFC3339, createdAt) 206 if err != nil { 207 return nil, err 208 } 209 comment.Created = &createdAtTime 210 211 comments = append(comments, comment) 212 } 213 214 if err := rows.Err(); err != nil { 215 return nil, err 216 } 217 218 return comments, nil 219} 220 221func CloseIssue(e Execer, repoAt syntax.ATURI, issueId int) error { 222 _, err := e.Exec(`update issues set open = 0 where repo_at = ? and issue_id = ?`, repoAt, issueId) 223 return err 224} 225 226func ReopenIssue(e Execer, repoAt syntax.ATURI, issueId int) error { 227 _, err := e.Exec(`update issues set open = 1 where repo_at = ? and issue_id = ?`, repoAt, issueId) 228 return err 229} 230 231type IssueCount struct { 232 Open int 233 Closed int 234} 235 236func GetIssueCount(e Execer, repoAt syntax.ATURI) (IssueCount, error) { 237 row := e.QueryRow(` 238 select 239 count(case when open = 1 then 1 end) as open_count, 240 count(case when open = 0 then 1 end) as closed_count 241 from issues 242 where repo_at = ?`, 243 repoAt, 244 ) 245 246 var count IssueCount 247 if err := row.Scan(&count.Open, &count.Closed); err != nil { 248 return IssueCount{0, 0}, err 249 } 250 251 return count, nil 252}